]> git.proxmox.com Git - mirror_ubuntu-kernels.git/commitdiff
Merge tag 'irq-core-2022-01-13' of git://git.kernel.org/pub/scm/linux/kernel/git...
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 13 Jan 2022 16:53:45 +0000 (08:53 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 13 Jan 2022 16:53:45 +0000 (08:53 -0800)
Pull irq updates from Thomas Gleixner:
 "Updates for the interrupt subsystem:

  Core:

   - Provide a new interface for affinity hints to provide a separation
     between hint and actual affinity change which has become a hidden
     property of the current interface

   - Fix up the in tree usage of the affinity hint interfaces

  Drivers:

   - No new irqchip drivers!

   - Fix GICv3 redistributor table reservation with RT across kexec

   - Fix GICv4.1 redistributor view of the VPE table across kexec

   - Add support for extra interrupts on spear-shirq

   - Make obtaining some interrupts optional for the Renesas drivers

   - Various cleanups and bug fixes"

* tag 'irq-core-2022-01-13' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (25 commits)
  irqchip/renesas-intc-irqpin: Use platform_get_irq_optional() to get the interrupt
  irqchip/renesas-irqc: Use platform_get_irq_optional() to get the interrupt
  irqchip/gic-v4: Disable redistributors' view of the VPE table at boot time
  irqchip/ingenic-tcu: Use correctly sized arguments for bit field
  irqchip/gic-v2m: Add const to of_device_id
  irqchip/imx-gpcv2: Mark imx_gpcv2_instance with __ro_after_init
  irqchip/spear-shirq: Add support for IRQ 0..6
  irqchip/gic-v3-its: Limit memreserve cpuhp state lifetime
  irqchip/gic-v3-its: Postpone LPI pending table freeing and memreserve
  irqchip/gic-v3-its: Give the percpu rdist struct its own flags field
  net/mlx4: Use irq_update_affinity_hint()
  net/mlx5: Use irq_set_affinity_and_hint()
  hinic: Use irq_set_affinity_and_hint()
  scsi: lpfc: Use irq_set_affinity()
  mailbox: Use irq_update_affinity_hint()
  ixgbe: Use irq_update_affinity_hint()
  be2net: Use irq_update_affinity_hint()
  enic: Use irq_update_affinity_hint()
  RDMA/irdma: Use irq_update_affinity_hint()
  scsi: mpt3sas: Use irq_set_affinity_and_hint()
  ...

1  2 
drivers/net/ethernet/cisco/enic/enic_main.c
drivers/net/ethernet/emulex/benet/be_main.c
drivers/net/ethernet/intel/iavf/iavf_main.c
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
drivers/net/ethernet/mellanox/mlx5/core/pci_irq.c

index 4db6889b79ba96075312517b798f7b93269f4e7c,2faba079b4fbc9ef0cf5a65886ed590791dcac3c..1c81b161de52b14fd6961633ccb1b1f99ef6f2f6
@@@ -150,10 -150,10 +150,10 @@@ static void enic_set_affinity_hint(stru
                    !cpumask_available(enic->msix[i].affinity_mask) ||
                    cpumask_empty(enic->msix[i].affinity_mask))
                        continue;
-               err = irq_set_affinity_hint(enic->msix_entry[i].vector,
-                                           enic->msix[i].affinity_mask);
+               err = irq_update_affinity_hint(enic->msix_entry[i].vector,
+                                              enic->msix[i].affinity_mask);
                if (err)
-                       netdev_warn(enic->netdev, "irq_set_affinity_hint failed, err %d\n",
+                       netdev_warn(enic->netdev, "irq_update_affinity_hint failed, err %d\n",
                                    err);
        }
  
@@@ -173,7 -173,7 +173,7 @@@ static void enic_unset_affinity_hint(st
        int i;
  
        for (i = 0; i < enic->intr_count; i++)
-               irq_set_affinity_hint(enic->msix_entry[i].vector, NULL);
+               irq_update_affinity_hint(enic->msix_entry[i].vector, NULL);
  }
  
  static int enic_udp_tunnel_set_port(struct net_device *netdev,
@@@ -2718,14 -2718,26 +2718,14 @@@ static int enic_probe(struct pci_dev *p
         * fail to 32-bit.
         */
  
 -      err = dma_set_mask(&pdev->dev, DMA_BIT_MASK(47));
 +      err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(47));
        if (err) {
 -              err = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
 +              err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
                if (err) {
                        dev_err(dev, "No usable DMA configuration, aborting\n");
                        goto err_out_release_regions;
                }
 -              err = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
 -              if (err) {
 -                      dev_err(dev, "Unable to obtain %u-bit DMA "
 -                              "for consistent allocations, aborting\n", 32);
 -                      goto err_out_release_regions;
 -              }
        } else {
 -              err = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(47));
 -              if (err) {
 -                      dev_err(dev, "Unable to obtain %u-bit DMA "
 -                              "for consistent allocations, aborting\n", 47);
 -                      goto err_out_release_regions;
 -              }
                using_dac = 1;
        }
  
index ad67b42160795a8de7003bcd54e8fc0559276f55,84b3ba9bdb18ada54039958da2368f9a318b871b..d0c262f2695a9afcc06ae479754e7695ff1d780f
@@@ -3491,7 -3491,7 +3491,7 @@@ static int be_msix_register(struct be_a
                if (status)
                        goto err_msix;
  
-               irq_set_affinity_hint(vec, eqo->affinity_mask);
+               irq_update_affinity_hint(vec, eqo->affinity_mask);
        }
  
        return 0;
@@@ -3552,7 -3552,7 +3552,7 @@@ static void be_irq_unregister(struct be
        /* MSIx */
        for_all_evt_queues(adapter, eqo, i) {
                vec = be_msix_vec_get(adapter, eqo);
-               irq_set_affinity_hint(vec, NULL);
+               irq_update_affinity_hint(vec, NULL);
                free_irq(vec, eqo);
        }
  
@@@ -5194,8 -5194,7 +5194,8 @@@ static void be_netdev_init(struct net_d
                netdev->hw_features |= NETIF_F_RXHASH;
  
        netdev->features |= netdev->hw_features |
 -              NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HW_VLAN_CTAG_FILTER;
 +              NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HW_VLAN_CTAG_FILTER |
 +              NETIF_F_HIGHDMA;
  
        netdev->vlan_features |= NETIF_F_SG | NETIF_F_TSO | NETIF_F_TSO6 |
                NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
@@@ -5841,9 -5840,14 +5841,9 @@@ static int be_probe(struct pci_dev *pde
        SET_NETDEV_DEV(netdev, &pdev->dev);
  
        status = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
 -      if (!status) {
 -              netdev->features |= NETIF_F_HIGHDMA;
 -      } else {
 -              status = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
 -              if (status) {
 -                      dev_err(&pdev->dev, "Could not set PCI DMA Mask\n");
 -                      goto free_netdev;
 -              }
 +      if (status) {
 +              dev_err(&pdev->dev, "Could not set PCI DMA Mask\n");
 +              goto free_netdev;
        }
  
        status = pci_enable_pcie_error_reporting(pdev);
index 95116ef2f0ae809b1442b2a7cf92bc5b2a0ea2ff,b1c161f9d706a7ec5eba7845d164d359e257b3ee..8125b91206150988e1ded404c7de85b663c4bb0a
@@@ -463,14 -463,14 +463,14 @@@ iavf_request_traffic_irqs(struct iavf_a
  
                if (q_vector->tx.ring && q_vector->rx.ring) {
                        snprintf(q_vector->name, sizeof(q_vector->name),
 -                               "iavf-%s-TxRx-%d", basename, rx_int_idx++);
 +                               "iavf-%s-TxRx-%u", basename, rx_int_idx++);
                        tx_int_idx++;
                } else if (q_vector->rx.ring) {
                        snprintf(q_vector->name, sizeof(q_vector->name),
 -                               "iavf-%s-rx-%d", basename, rx_int_idx++);
 +                               "iavf-%s-rx-%u", basename, rx_int_idx++);
                } else if (q_vector->tx.ring) {
                        snprintf(q_vector->name, sizeof(q_vector->name),
 -                               "iavf-%s-tx-%d", basename, tx_int_idx++);
 +                               "iavf-%s-tx-%u", basename, tx_int_idx++);
                } else {
                        /* skip this unused q_vector */
                        continue;
                irq_set_affinity_notifier(irq_num, &q_vector->affinity_notify);
                /* Spread the IRQ affinity hints across online CPUs. Note that
                 * get_cpu_mask returns a mask with a permanent lifetime so
-                * it's safe to use as a hint for irq_set_affinity_hint.
+                * it's safe to use as a hint for irq_update_affinity_hint.
                 */
                cpu = cpumask_local_spread(q_vector->v_idx, -1);
-               irq_set_affinity_hint(irq_num, get_cpu_mask(cpu));
+               irq_update_affinity_hint(irq_num, get_cpu_mask(cpu));
        }
  
        return 0;
@@@ -505,7 -505,7 +505,7 @@@ free_queue_irqs
                vector--;
                irq_num = adapter->msix_entries[vector + NONQ_VECS].vector;
                irq_set_affinity_notifier(irq_num, NULL);
-               irq_set_affinity_hint(irq_num, NULL);
+               irq_update_affinity_hint(irq_num, NULL);
                free_irq(irq_num, &adapter->q_vectors[vector]);
        }
        return err;
@@@ -557,7 -557,7 +557,7 @@@ static void iavf_free_traffic_irqs(stru
        for (vector = 0; vector < q_vectors; vector++) {
                irq_num = adapter->msix_entries[vector + NONQ_VECS].vector;
                irq_set_affinity_notifier(irq_num, NULL);
-               irq_set_affinity_hint(irq_num, NULL);
+               irq_update_affinity_hint(irq_num, NULL);
                free_irq(irq_num, &adapter->q_vectors[vector]);
        }
  }
@@@ -646,17 -646,14 +646,17 @@@ static void iavf_configure_rx(struct ia
   * mac_vlan_list_lock.
   **/
  static struct
 -iavf_vlan_filter *iavf_find_vlan(struct iavf_adapter *adapter, u16 vlan)
 +iavf_vlan_filter *iavf_find_vlan(struct iavf_adapter *adapter,
 +                               struct iavf_vlan vlan)
  {
        struct iavf_vlan_filter *f;
  
        list_for_each_entry(f, &adapter->vlan_filter_list, list) {
 -              if (vlan == f->vlan)
 +              if (f->vlan.vid == vlan.vid &&
 +                  f->vlan.tpid == vlan.tpid)
                        return f;
        }
 +
        return NULL;
  }
  
   * Returns ptr to the filter object or NULL when no memory available.
   **/
  static struct
 -iavf_vlan_filter *iavf_add_vlan(struct iavf_adapter *adapter, u16 vlan)
 +iavf_vlan_filter *iavf_add_vlan(struct iavf_adapter *adapter,
 +                              struct iavf_vlan vlan)
  {
        struct iavf_vlan_filter *f = NULL;
  
@@@ -698,7 -694,7 +698,7 @@@ clearout
   * @adapter: board private structure
   * @vlan: VLAN tag
   **/
 -static void iavf_del_vlan(struct iavf_adapter *adapter, u16 vlan)
 +static void iavf_del_vlan(struct iavf_adapter *adapter, struct iavf_vlan vlan)
  {
        struct iavf_vlan_filter *f;
  
@@@ -724,55 -720,8 +724,55 @@@ static void iavf_restore_filters(struc
        u16 vid;
  
        /* re-add all VLAN filters */
 -      for_each_set_bit(vid, adapter->vsi.active_vlans, VLAN_N_VID)
 -              iavf_add_vlan(adapter, vid);
 +      for_each_set_bit(vid, adapter->vsi.active_cvlans, VLAN_N_VID)
 +              iavf_add_vlan(adapter, IAVF_VLAN(vid, ETH_P_8021Q));
 +
 +      for_each_set_bit(vid, adapter->vsi.active_svlans, VLAN_N_VID)
 +              iavf_add_vlan(adapter, IAVF_VLAN(vid, ETH_P_8021AD));
 +}
 +
 +/**
 + * iavf_get_num_vlans_added - get number of VLANs added
 + * @adapter: board private structure
 + */
 +static u16 iavf_get_num_vlans_added(struct iavf_adapter *adapter)
 +{
 +      return bitmap_weight(adapter->vsi.active_cvlans, VLAN_N_VID) +
 +              bitmap_weight(adapter->vsi.active_svlans, VLAN_N_VID);
 +}
 +
 +/**
 + * iavf_get_max_vlans_allowed - get maximum VLANs allowed for this VF
 + * @adapter: board private structure
 + *
 + * This depends on the negotiated VLAN capability. For VIRTCHNL_VF_OFFLOAD_VLAN,
 + * do not impose a limit as that maintains current behavior and for
 + * VIRTCHNL_VF_OFFLOAD_VLAN_V2, use the maximum allowed sent from the PF.
 + **/
 +static u16 iavf_get_max_vlans_allowed(struct iavf_adapter *adapter)
 +{
 +      /* don't impose any limit for VIRTCHNL_VF_OFFLOAD_VLAN since there has
 +       * never been a limit on the VF driver side
 +       */
 +      if (VLAN_ALLOWED(adapter))
 +              return VLAN_N_VID;
 +      else if (VLAN_V2_ALLOWED(adapter))
 +              return adapter->vlan_v2_caps.filtering.max_filters;
 +
 +      return 0;
 +}
 +
 +/**
 + * iavf_max_vlans_added - check if maximum VLANs allowed already exist
 + * @adapter: board private structure
 + **/
 +static bool iavf_max_vlans_added(struct iavf_adapter *adapter)
 +{
 +      if (iavf_get_num_vlans_added(adapter) <
 +          iavf_get_max_vlans_allowed(adapter))
 +              return false;
 +
 +      return true;
  }
  
  /**
@@@ -786,23 -735,13 +786,23 @@@ static int iavf_vlan_rx_add_vid(struct 
  {
        struct iavf_adapter *adapter = netdev_priv(netdev);
  
 -      if (!VLAN_ALLOWED(adapter))
 +      if (!VLAN_FILTERING_ALLOWED(adapter))
 +              return -EIO;
 +
 +      if (iavf_max_vlans_added(adapter)) {
 +              netdev_err(netdev, "Max allowed VLAN filters %u. Remove existing VLANs or disable filtering via Ethtool if supported.\n",
 +                         iavf_get_max_vlans_allowed(adapter));
                return -EIO;
 +      }
  
 -      if (iavf_add_vlan(adapter, vid) == NULL)
 +      if (!iavf_add_vlan(adapter, IAVF_VLAN(vid, be16_to_cpu(proto))))
                return -ENOMEM;
  
 -      set_bit(vid, adapter->vsi.active_vlans);
 +      if (proto == cpu_to_be16(ETH_P_8021Q))
 +              set_bit(vid, adapter->vsi.active_cvlans);
 +      else
 +              set_bit(vid, adapter->vsi.active_svlans);
 +
        return 0;
  }
  
@@@ -817,11 -756,8 +817,11 @@@ static int iavf_vlan_rx_kill_vid(struc
  {
        struct iavf_adapter *adapter = netdev_priv(netdev);
  
 -      iavf_del_vlan(adapter, vid);
 -      clear_bit(vid, adapter->vsi.active_vlans);
 +      iavf_del_vlan(adapter, IAVF_VLAN(vid, be16_to_cpu(proto)));
 +      if (proto == cpu_to_be16(ETH_P_8021Q))
 +              clear_bit(vid, adapter->vsi.active_cvlans);
 +      else
 +              clear_bit(vid, adapter->vsi.active_svlans);
  
        return 0;
  }
@@@ -1215,86 -1151,6 +1215,86 @@@ static void iavf_free_queues(struct iav
        adapter->rx_rings = NULL;
  }
  
 +/**
 + * iavf_set_queue_vlan_tag_loc - set location for VLAN tag offload
 + * @adapter: board private structure
 + *
 + * Based on negotiated capabilities, the VLAN tag needs to be inserted and/or
 + * stripped in certain descriptor fields. Instead of checking the offload
 + * capability bits in the hot path, cache the location the ring specific
 + * flags.
 + */
 +void iavf_set_queue_vlan_tag_loc(struct iavf_adapter *adapter)
 +{
 +      int i;
 +
 +      for (i = 0; i < adapter->num_active_queues; i++) {
 +              struct iavf_ring *tx_ring = &adapter->tx_rings[i];
 +              struct iavf_ring *rx_ring = &adapter->rx_rings[i];
 +
 +              /* prevent multiple L2TAG bits being set after VFR */
 +              tx_ring->flags &=
 +                      ~(IAVF_TXRX_FLAGS_VLAN_TAG_LOC_L2TAG1 |
 +                        IAVF_TXR_FLAGS_VLAN_TAG_LOC_L2TAG2);
 +              rx_ring->flags &=
 +                      ~(IAVF_TXRX_FLAGS_VLAN_TAG_LOC_L2TAG1 |
 +                        IAVF_RXR_FLAGS_VLAN_TAG_LOC_L2TAG2_2);
 +
 +              if (VLAN_ALLOWED(adapter)) {
 +                      tx_ring->flags |= IAVF_TXRX_FLAGS_VLAN_TAG_LOC_L2TAG1;
 +                      rx_ring->flags |= IAVF_TXRX_FLAGS_VLAN_TAG_LOC_L2TAG1;
 +              } else if (VLAN_V2_ALLOWED(adapter)) {
 +                      struct virtchnl_vlan_supported_caps *stripping_support;
 +                      struct virtchnl_vlan_supported_caps *insertion_support;
 +
 +                      stripping_support =
 +                              &adapter->vlan_v2_caps.offloads.stripping_support;
 +                      insertion_support =
 +                              &adapter->vlan_v2_caps.offloads.insertion_support;
 +
 +                      if (stripping_support->outer) {
 +                              if (stripping_support->outer &
 +                                  VIRTCHNL_VLAN_TAG_LOCATION_L2TAG1)
 +                                      rx_ring->flags |=
 +                                              IAVF_TXRX_FLAGS_VLAN_TAG_LOC_L2TAG1;
 +                              else if (stripping_support->outer &
 +                                       VIRTCHNL_VLAN_TAG_LOCATION_L2TAG2_2)
 +                                      rx_ring->flags |=
 +                                              IAVF_RXR_FLAGS_VLAN_TAG_LOC_L2TAG2_2;
 +                      } else if (stripping_support->inner) {
 +                              if (stripping_support->inner &
 +                                  VIRTCHNL_VLAN_TAG_LOCATION_L2TAG1)
 +                                      rx_ring->flags |=
 +                                              IAVF_TXRX_FLAGS_VLAN_TAG_LOC_L2TAG1;
 +                              else if (stripping_support->inner &
 +                                       VIRTCHNL_VLAN_TAG_LOCATION_L2TAG2_2)
 +                                      rx_ring->flags |=
 +                                              IAVF_RXR_FLAGS_VLAN_TAG_LOC_L2TAG2_2;
 +                      }
 +
 +                      if (insertion_support->outer) {
 +                              if (insertion_support->outer &
 +                                  VIRTCHNL_VLAN_TAG_LOCATION_L2TAG1)
 +                                      tx_ring->flags |=
 +                                              IAVF_TXRX_FLAGS_VLAN_TAG_LOC_L2TAG1;
 +                              else if (insertion_support->outer &
 +                                       VIRTCHNL_VLAN_TAG_LOCATION_L2TAG2)
 +                                      tx_ring->flags |=
 +                                              IAVF_TXR_FLAGS_VLAN_TAG_LOC_L2TAG2;
 +                      } else if (insertion_support->inner) {
 +                              if (insertion_support->inner &
 +                                  VIRTCHNL_VLAN_TAG_LOCATION_L2TAG1)
 +                                      tx_ring->flags |=
 +                                              IAVF_TXRX_FLAGS_VLAN_TAG_LOC_L2TAG1;
 +                              else if (insertion_support->inner &
 +                                       VIRTCHNL_VLAN_TAG_LOCATION_L2TAG2)
 +                                      tx_ring->flags |=
 +                                              IAVF_TXR_FLAGS_VLAN_TAG_LOC_L2TAG2;
 +                      }
 +              }
 +      }
 +}
 +
  /**
   * iavf_alloc_queues - Allocate memory for all rings
   * @adapter: board private structure to initialize
@@@ -1356,8 -1212,6 +1356,8 @@@ static int iavf_alloc_queues(struct iav
  
        adapter->num_active_queues = num_active_queues;
  
 +      iavf_set_queue_vlan_tag_loc(adapter);
 +
        return 0;
  
  err_out:
@@@ -1730,8 -1584,6 +1730,8 @@@ static int iavf_process_aq_command(stru
  {
        if (adapter->aq_required & IAVF_FLAG_AQ_GET_CONFIG)
                return iavf_send_vf_config_msg(adapter);
 +      if (adapter->aq_required & IAVF_FLAG_AQ_GET_OFFLOAD_VLAN_V2_CAPS)
 +              return iavf_send_vf_offload_vlan_v2_msg(adapter);
        if (adapter->aq_required & IAVF_FLAG_AQ_DISABLE_QUEUES) {
                iavf_disable_queues(adapter);
                return 0;
                iavf_del_adv_rss_cfg(adapter);
                return 0;
        }
 +      if (adapter->aq_required & IAVF_FLAG_AQ_DISABLE_CTAG_VLAN_STRIPPING) {
 +              iavf_disable_vlan_stripping_v2(adapter, ETH_P_8021Q);
 +              return 0;
 +      }
 +      if (adapter->aq_required & IAVF_FLAG_AQ_DISABLE_STAG_VLAN_STRIPPING) {
 +              iavf_disable_vlan_stripping_v2(adapter, ETH_P_8021AD);
 +              return 0;
 +      }
 +      if (adapter->aq_required & IAVF_FLAG_AQ_ENABLE_CTAG_VLAN_STRIPPING) {
 +              iavf_enable_vlan_stripping_v2(adapter, ETH_P_8021Q);
 +              return 0;
 +      }
 +      if (adapter->aq_required & IAVF_FLAG_AQ_ENABLE_STAG_VLAN_STRIPPING) {
 +              iavf_enable_vlan_stripping_v2(adapter, ETH_P_8021AD);
 +              return 0;
 +      }
 +      if (adapter->aq_required & IAVF_FLAG_AQ_DISABLE_CTAG_VLAN_INSERTION) {
 +              iavf_disable_vlan_insertion_v2(adapter, ETH_P_8021Q);
 +              return 0;
 +      }
 +      if (adapter->aq_required & IAVF_FLAG_AQ_DISABLE_STAG_VLAN_INSERTION) {
 +              iavf_disable_vlan_insertion_v2(adapter, ETH_P_8021AD);
 +              return 0;
 +      }
 +      if (adapter->aq_required & IAVF_FLAG_AQ_ENABLE_CTAG_VLAN_INSERTION) {
 +              iavf_enable_vlan_insertion_v2(adapter, ETH_P_8021Q);
 +              return 0;
 +      }
 +      if (adapter->aq_required & IAVF_FLAG_AQ_ENABLE_STAG_VLAN_INSERTION) {
 +              iavf_enable_vlan_insertion_v2(adapter, ETH_P_8021AD);
 +              return 0;
 +      }
 +
        if (adapter->aq_required & IAVF_FLAG_AQ_REQUEST_STATS) {
                iavf_request_stats(adapter);
                return 0;
        return -EAGAIN;
  }
  
 +/**
 + * iavf_set_vlan_offload_features - set VLAN offload configuration
 + * @adapter: board private structure
 + * @prev_features: previous features used for comparison
 + * @features: updated features used for configuration
 + *
 + * Set the aq_required bit(s) based on the requested features passed in to
 + * configure VLAN stripping and/or VLAN insertion if supported. Also, schedule
 + * the watchdog if any changes are requested to expedite the request via
 + * virtchnl.
 + **/
 +void
 +iavf_set_vlan_offload_features(struct iavf_adapter *adapter,
 +                             netdev_features_t prev_features,
 +                             netdev_features_t features)
 +{
 +      bool enable_stripping = true, enable_insertion = true;
 +      u16 vlan_ethertype = 0;
 +      u64 aq_required = 0;
 +
 +      /* keep cases separate because one ethertype for offloads can be
 +       * disabled at the same time as another is disabled, so check for an
 +       * enabled ethertype first, then check for disabled. Default to
 +       * ETH_P_8021Q so an ethertype is specified if disabling insertion and
 +       * stripping.
 +       */
 +      if (features & (NETIF_F_HW_VLAN_STAG_RX | NETIF_F_HW_VLAN_STAG_TX))
 +              vlan_ethertype = ETH_P_8021AD;
 +      else if (features & (NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HW_VLAN_CTAG_TX))
 +              vlan_ethertype = ETH_P_8021Q;
 +      else if (prev_features & (NETIF_F_HW_VLAN_STAG_RX | NETIF_F_HW_VLAN_STAG_TX))
 +              vlan_ethertype = ETH_P_8021AD;
 +      else if (prev_features & (NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HW_VLAN_CTAG_TX))
 +              vlan_ethertype = ETH_P_8021Q;
 +      else
 +              vlan_ethertype = ETH_P_8021Q;
 +
 +      if (!(features & (NETIF_F_HW_VLAN_STAG_RX | NETIF_F_HW_VLAN_CTAG_RX)))
 +              enable_stripping = false;
 +      if (!(features & (NETIF_F_HW_VLAN_STAG_TX | NETIF_F_HW_VLAN_CTAG_TX)))
 +              enable_insertion = false;
 +
 +      if (VLAN_ALLOWED(adapter)) {
 +              /* VIRTCHNL_VF_OFFLOAD_VLAN only has support for toggling VLAN
 +               * stripping via virtchnl. VLAN insertion can be toggled on the
 +               * netdev, but it doesn't require a virtchnl message
 +               */
 +              if (enable_stripping)
 +                      aq_required |= IAVF_FLAG_AQ_ENABLE_VLAN_STRIPPING;
 +              else
 +                      aq_required |= IAVF_FLAG_AQ_DISABLE_VLAN_STRIPPING;
 +
 +      } else if (VLAN_V2_ALLOWED(adapter)) {
 +              switch (vlan_ethertype) {
 +              case ETH_P_8021Q:
 +                      if (enable_stripping)
 +                              aq_required |= IAVF_FLAG_AQ_ENABLE_CTAG_VLAN_STRIPPING;
 +                      else
 +                              aq_required |= IAVF_FLAG_AQ_DISABLE_CTAG_VLAN_STRIPPING;
 +
 +                      if (enable_insertion)
 +                              aq_required |= IAVF_FLAG_AQ_ENABLE_CTAG_VLAN_INSERTION;
 +                      else
 +                              aq_required |= IAVF_FLAG_AQ_DISABLE_CTAG_VLAN_INSERTION;
 +                      break;
 +              case ETH_P_8021AD:
 +                      if (enable_stripping)
 +                              aq_required |= IAVF_FLAG_AQ_ENABLE_STAG_VLAN_STRIPPING;
 +                      else
 +                              aq_required |= IAVF_FLAG_AQ_DISABLE_STAG_VLAN_STRIPPING;
 +
 +                      if (enable_insertion)
 +                              aq_required |= IAVF_FLAG_AQ_ENABLE_STAG_VLAN_INSERTION;
 +                      else
 +                              aq_required |= IAVF_FLAG_AQ_DISABLE_STAG_VLAN_INSERTION;
 +                      break;
 +              }
 +      }
 +
 +      if (aq_required) {
 +              adapter->aq_required |= aq_required;
 +              mod_delayed_work(iavf_wq, &adapter->watchdog_task, 0);
 +      }
 +}
 +
  /**
   * iavf_startup - first step of driver startup
   * @adapter: board private structure
        iavf_change_state(adapter, __IAVF_INIT_FAILED);
  }
  
 +/**
 + * iavf_parse_vf_resource_msg - parse response from VIRTCHNL_OP_GET_VF_RESOURCES
 + * @adapter: board private structure
 + */
 +int iavf_parse_vf_resource_msg(struct iavf_adapter *adapter)
 +{
 +      int i, num_req_queues = adapter->num_req_queues;
 +      struct iavf_vsi *vsi = &adapter->vsi;
 +
 +      for (i = 0; i < adapter->vf_res->num_vsis; i++) {
 +              if (adapter->vf_res->vsi_res[i].vsi_type == VIRTCHNL_VSI_SRIOV)
 +                      adapter->vsi_res = &adapter->vf_res->vsi_res[i];
 +      }
 +      if (!adapter->vsi_res) {
 +              dev_err(&adapter->pdev->dev, "No LAN VSI found\n");
 +              return -ENODEV;
 +      }
 +
 +      if (num_req_queues &&
 +          num_req_queues > adapter->vsi_res->num_queue_pairs) {
 +              /* Problem.  The PF gave us fewer queues than what we had
 +               * negotiated in our request.  Need a reset to see if we can't
 +               * get back to a working state.
 +               */
 +              dev_err(&adapter->pdev->dev,
 +                      "Requested %d queues, but PF only gave us %d.\n",
 +                      num_req_queues,
 +                      adapter->vsi_res->num_queue_pairs);
 +              adapter->flags |= IAVF_FLAG_REINIT_ITR_NEEDED;
 +              adapter->num_req_queues = adapter->vsi_res->num_queue_pairs;
 +              iavf_schedule_reset(adapter);
 +
 +              return -EAGAIN;
 +      }
 +      adapter->num_req_queues = 0;
 +      adapter->vsi.id = adapter->vsi_res->vsi_id;
 +
 +      adapter->vsi.back = adapter;
 +      adapter->vsi.base_vector = 1;
 +      adapter->vsi.work_limit = IAVF_DEFAULT_IRQ_WORK;
 +      vsi->netdev = adapter->netdev;
 +      vsi->qs_handle = adapter->vsi_res->qset_handle;
 +      if (adapter->vf_res->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_RSS_PF) {
 +              adapter->rss_key_size = adapter->vf_res->rss_key_size;
 +              adapter->rss_lut_size = adapter->vf_res->rss_lut_size;
 +      } else {
 +              adapter->rss_key_size = IAVF_HKEY_ARRAY_SIZE;
 +              adapter->rss_lut_size = IAVF_HLUT_ARRAY_SIZE;
 +      }
 +
 +      return 0;
 +}
 +
  /**
   * iavf_init_get_resources - third step of driver startup
   * @adapter: board private structure
   **/
  static void iavf_init_get_resources(struct iavf_adapter *adapter)
  {
 -      struct net_device *netdev = adapter->netdev;
        struct pci_dev *pdev = adapter->pdev;
        struct iavf_hw *hw = &adapter->hw;
        int err;
        err = iavf_get_vf_config(adapter);
        if (err == IAVF_ERR_ADMIN_QUEUE_NO_WORK) {
                err = iavf_send_vf_config_msg(adapter);
 -              goto err;
 +              goto err_alloc;
        } else if (err == IAVF_ERR_PARAM) {
                /* We only get ERR_PARAM if the device is in a very bad
                 * state or if we've been disabled for previous bad
                goto err_alloc;
        }
  
 -      err = iavf_process_config(adapter);
 +      err = iavf_parse_vf_resource_msg(adapter);
        if (err)
                goto err_alloc;
 +
 +      err = iavf_send_vf_offload_vlan_v2_msg(adapter);
 +      if (err == -EOPNOTSUPP) {
 +              /* underlying PF doesn't support VIRTCHNL_VF_OFFLOAD_VLAN_V2, so
 +               * go directly to finishing initialization
 +               */
 +              iavf_change_state(adapter, __IAVF_INIT_CONFIG_ADAPTER);
 +              return;
 +      } else if (err) {
 +              dev_err(&pdev->dev, "Unable to send offload vlan v2 request (%d)\n",
 +                      err);
 +              goto err_alloc;
 +      }
 +
 +      /* underlying PF supports VIRTCHNL_VF_OFFLOAD_VLAN_V2, so update the
 +       * state accordingly
 +       */
 +      iavf_change_state(adapter, __IAVF_INIT_GET_OFFLOAD_VLAN_V2_CAPS);
 +      return;
 +
 +err_alloc:
 +      kfree(adapter->vf_res);
 +      adapter->vf_res = NULL;
 +err:
 +      iavf_change_state(adapter, __IAVF_INIT_FAILED);
 +}
 +
 +/**
 + * iavf_init_get_offload_vlan_v2_caps - part of driver startup
 + * @adapter: board private structure
 + *
 + * Function processes __IAVF_INIT_GET_OFFLOAD_VLAN_V2_CAPS driver state if the
 + * VF negotiates VIRTCHNL_VF_OFFLOAD_VLAN_V2. If VIRTCHNL_VF_OFFLOAD_VLAN_V2 is
 + * not negotiated, then this state will never be entered.
 + **/
 +static void iavf_init_get_offload_vlan_v2_caps(struct iavf_adapter *adapter)
 +{
 +      int ret;
 +
 +      WARN_ON(adapter->state != __IAVF_INIT_GET_OFFLOAD_VLAN_V2_CAPS);
 +
 +      memset(&adapter->vlan_v2_caps, 0, sizeof(adapter->vlan_v2_caps));
 +
 +      ret = iavf_get_vf_vlan_v2_caps(adapter);
 +      if (ret) {
 +              if (ret == IAVF_ERR_ADMIN_QUEUE_NO_WORK)
 +                      iavf_send_vf_offload_vlan_v2_msg(adapter);
 +              goto err;
 +      }
 +
 +      iavf_change_state(adapter, __IAVF_INIT_CONFIG_ADAPTER);
 +      return;
 +err:
 +      iavf_change_state(adapter, __IAVF_INIT_FAILED);
 +}
 +
 +/**
 + * iavf_init_config_adapter - last part of driver startup
 + * @adapter: board private structure
 + *
 + * After all the supported capabilities are negotiated, then the
 + * __IAVF_INIT_CONFIG_ADAPTER state will finish driver initialization.
 + */
 +static void iavf_init_config_adapter(struct iavf_adapter *adapter)
 +{
 +      struct net_device *netdev = adapter->netdev;
 +      struct pci_dev *pdev = adapter->pdev;
 +      int err;
 +
 +      WARN_ON(adapter->state != __IAVF_INIT_CONFIG_ADAPTER);
 +
 +      if (iavf_process_config(adapter))
 +              goto err;
 +
        adapter->current_op = VIRTCHNL_OP_UNKNOWN;
  
        adapter->flags |= IAVF_FLAG_RX_CSUM_ENABLED;
        else
                iavf_init_rss(adapter);
  
 +      if (VLAN_V2_ALLOWED(adapter))
 +              /* request initial VLAN offload settings */
 +              iavf_set_vlan_offload_features(adapter, 0, netdev->features);
 +
        return;
  err_mem:
        iavf_free_rss(adapter);
@@@ -2358,6 -1962,9 +2358,6 @@@ err_register
        iavf_free_misc_irq(adapter);
  err_sw_init:
        iavf_reset_interrupt_capability(adapter);
 -err_alloc:
 -      kfree(adapter->vf_res);
 -      adapter->vf_res = NULL;
  err:
        iavf_change_state(adapter, __IAVF_INIT_FAILED);
  }
@@@ -2406,18 -2013,6 +2406,18 @@@ static void iavf_watchdog_task(struct w
                queue_delayed_work(iavf_wq, &adapter->watchdog_task,
                                   msecs_to_jiffies(1));
                return;
 +      case __IAVF_INIT_GET_OFFLOAD_VLAN_V2_CAPS:
 +              iavf_init_get_offload_vlan_v2_caps(adapter);
 +              mutex_unlock(&adapter->crit_lock);
 +              queue_delayed_work(iavf_wq, &adapter->watchdog_task,
 +                                 msecs_to_jiffies(1));
 +              return;
 +      case __IAVF_INIT_CONFIG_ADAPTER:
 +              iavf_init_config_adapter(adapter);
 +              mutex_unlock(&adapter->crit_lock);
 +              queue_delayed_work(iavf_wq, &adapter->watchdog_task,
 +                                 msecs_to_jiffies(1));
 +              return;
        case __IAVF_INIT_FAILED:
                if (++adapter->aq_wait_count > IAVF_AQ_MAX_ERR) {
                        dev_err(&adapter->pdev->dev,
                                iavf_send_api_ver(adapter);
                        }
                } else {
 +                      int ret = iavf_process_aq_command(adapter);
 +
                        /* An error will be returned if no commands were
                         * processed; use this opportunity to update stats
 +                       * if the error isn't -ENOTSUPP
                         */
 -                      if (iavf_process_aq_command(adapter) &&
 +                      if (ret && ret != -EOPNOTSUPP &&
                            adapter->state == __IAVF_RUNNING)
                                iavf_request_stats(adapter);
                }
@@@ -2716,13 -2308,6 +2716,13 @@@ continue_reset
        }
  
        adapter->aq_required |= IAVF_FLAG_AQ_GET_CONFIG;
 +      /* always set since VIRTCHNL_OP_GET_VF_RESOURCES has not been
 +       * sent/received yet, so VLAN_V2_ALLOWED() cannot is not reliable here,
 +       * however the VIRTCHNL_OP_GET_OFFLOAD_VLAN_V2_CAPS won't be sent until
 +       * VIRTCHNL_OP_GET_VF_RESOURCES and VIRTCHNL_VF_OFFLOAD_VLAN_V2 have
 +       * been successfully sent and negotiated
 +       */
 +      adapter->aq_required |= IAVF_FLAG_AQ_GET_OFFLOAD_VLAN_V2_CAPS;
        adapter->aq_required |= IAVF_FLAG_AQ_MAP_VECTORS;
  
        spin_lock_bh(&adapter->mac_vlan_list_lock);
@@@ -3328,7 -2913,7 +3328,7 @@@ static int iavf_parse_cls_flower(struc
                        } else {
                                dev_err(&adapter->pdev->dev, "Bad ether dest mask %pM\n",
                                        match.mask->dst);
 -                              return IAVF_ERR_CONFIG;
 +                              return -EINVAL;
                        }
                }
  
                        } else {
                                dev_err(&adapter->pdev->dev, "Bad ether src mask %pM\n",
                                        match.mask->src);
 -                              return IAVF_ERR_CONFIG;
 +                              return -EINVAL;
                        }
                }
  
                        } else {
                                dev_err(&adapter->pdev->dev, "Bad vlan mask %u\n",
                                        match.mask->vlan_id);
 -                              return IAVF_ERR_CONFIG;
 +                              return -EINVAL;
                        }
                }
                vf->mask.tcp_spec.vlan_id |= cpu_to_be16(0xffff);
                        } else {
                                dev_err(&adapter->pdev->dev, "Bad ip dst mask 0x%08x\n",
                                        be32_to_cpu(match.mask->dst));
 -                              return IAVF_ERR_CONFIG;
 +                              return -EINVAL;
                        }
                }
  
                        } else {
                                dev_err(&adapter->pdev->dev, "Bad ip src mask 0x%08x\n",
                                        be32_to_cpu(match.mask->dst));
 -                              return IAVF_ERR_CONFIG;
 +                              return -EINVAL;
                        }
                }
  
                if (field_flags & IAVF_CLOUD_FIELD_TEN_ID) {
                        dev_info(&adapter->pdev->dev, "Tenant id not allowed for ip filter\n");
 -                      return IAVF_ERR_CONFIG;
 +                      return -EINVAL;
                }
                if (match.key->dst) {
                        vf->mask.tcp_spec.dst_ip[0] |= cpu_to_be32(0xffffffff);
                if (ipv6_addr_any(&match.mask->dst)) {
                        dev_err(&adapter->pdev->dev, "Bad ipv6 dst mask 0x%02x\n",
                                IPV6_ADDR_ANY);
 -                      return IAVF_ERR_CONFIG;
 +                      return -EINVAL;
                }
  
                /* src and dest IPv6 address should not be LOOPBACK
                    ipv6_addr_loopback(&match.key->src)) {
                        dev_err(&adapter->pdev->dev,
                                "ipv6 addr should not be loopback\n");
 -                      return IAVF_ERR_CONFIG;
 +                      return -EINVAL;
                }
                if (!ipv6_addr_any(&match.mask->dst) ||
                    !ipv6_addr_any(&match.mask->src))
                        } else {
                                dev_err(&adapter->pdev->dev, "Bad src port mask %u\n",
                                        be16_to_cpu(match.mask->src));
 -                              return IAVF_ERR_CONFIG;
 +                              return -EINVAL;
                        }
                }
  
                        } else {
                                dev_err(&adapter->pdev->dev, "Bad dst port mask %u\n",
                                        be16_to_cpu(match.mask->dst));
 -                              return IAVF_ERR_CONFIG;
 +                              return -EINVAL;
                        }
                }
                if (match.key->dst) {
@@@ -3846,8 -3431,6 +3846,8 @@@ static int iavf_change_mtu(struct net_d
  {
        struct iavf_adapter *adapter = netdev_priv(netdev);
  
 +      netdev_dbg(netdev, "changing MTU from %d to %d\n",
 +                 netdev->mtu, new_mtu);
        netdev->mtu = new_mtu;
        if (CLIENT_ENABLED(adapter)) {
                iavf_notify_client_l2_params(&adapter->vsi);
        return 0;
  }
  
 +#define NETIF_VLAN_OFFLOAD_FEATURES   (NETIF_F_HW_VLAN_CTAG_RX | \
 +                                       NETIF_F_HW_VLAN_CTAG_TX | \
 +                                       NETIF_F_HW_VLAN_STAG_RX | \
 +                                       NETIF_F_HW_VLAN_STAG_TX)
 +
  /**
   * iavf_set_features - set the netdev feature flags
   * @netdev: ptr to the netdev being adjusted
@@@ -3875,11 -3453,25 +3875,11 @@@ static int iavf_set_features(struct net
  {
        struct iavf_adapter *adapter = netdev_priv(netdev);
  
 -      /* Don't allow enabling VLAN features when adapter is not capable
 -       * of VLAN offload/filtering
 -       */
 -      if (!VLAN_ALLOWED(adapter)) {
 -              netdev->hw_features &= ~(NETIF_F_HW_VLAN_CTAG_RX |
 -                                       NETIF_F_HW_VLAN_CTAG_TX |
 -                                       NETIF_F_HW_VLAN_CTAG_FILTER);
 -              if (features & (NETIF_F_HW_VLAN_CTAG_RX |
 -                              NETIF_F_HW_VLAN_CTAG_TX |
 -                              NETIF_F_HW_VLAN_CTAG_FILTER))
 -                      return -EINVAL;
 -      } else if ((netdev->features ^ features) & NETIF_F_HW_VLAN_CTAG_RX) {
 -              if (features & NETIF_F_HW_VLAN_CTAG_RX)
 -                      adapter->aq_required |=
 -                              IAVF_FLAG_AQ_ENABLE_VLAN_STRIPPING;
 -              else
 -                      adapter->aq_required |=
 -                              IAVF_FLAG_AQ_DISABLE_VLAN_STRIPPING;
 -      }
 +      /* trigger update on any VLAN feature change */
 +      if ((netdev->features & NETIF_VLAN_OFFLOAD_FEATURES) ^
 +          (features & NETIF_VLAN_OFFLOAD_FEATURES))
 +              iavf_set_vlan_offload_features(adapter, netdev->features,
 +                                             features);
  
        return 0;
  }
@@@ -3942,228 -3534,6 +3942,228 @@@ out_err
        return features & ~(NETIF_F_CSUM_MASK | NETIF_F_GSO_MASK);
  }
  
 +/**
 + * iavf_get_netdev_vlan_hw_features - get NETDEV VLAN features that can toggle on/off
 + * @adapter: board private structure
 + *
 + * Depending on whether VIRTHCNL_VF_OFFLOAD_VLAN or VIRTCHNL_VF_OFFLOAD_VLAN_V2
 + * were negotiated determine the VLAN features that can be toggled on and off.
 + **/
 +static netdev_features_t
 +iavf_get_netdev_vlan_hw_features(struct iavf_adapter *adapter)
 +{
 +      netdev_features_t hw_features = 0;
 +
 +      if (!adapter->vf_res || !adapter->vf_res->vf_cap_flags)
 +              return hw_features;
 +
 +      /* Enable VLAN features if supported */
 +      if (VLAN_ALLOWED(adapter)) {
 +              hw_features |= (NETIF_F_HW_VLAN_CTAG_TX |
 +                              NETIF_F_HW_VLAN_CTAG_RX);
 +      } else if (VLAN_V2_ALLOWED(adapter)) {
 +              struct virtchnl_vlan_caps *vlan_v2_caps =
 +                      &adapter->vlan_v2_caps;
 +              struct virtchnl_vlan_supported_caps *stripping_support =
 +                      &vlan_v2_caps->offloads.stripping_support;
 +              struct virtchnl_vlan_supported_caps *insertion_support =
 +                      &vlan_v2_caps->offloads.insertion_support;
 +
 +              if (stripping_support->outer != VIRTCHNL_VLAN_UNSUPPORTED &&
 +                  stripping_support->outer & VIRTCHNL_VLAN_TOGGLE) {
 +                      if (stripping_support->outer &
 +                          VIRTCHNL_VLAN_ETHERTYPE_8100)
 +                              hw_features |= NETIF_F_HW_VLAN_CTAG_RX;
 +                      if (stripping_support->outer &
 +                          VIRTCHNL_VLAN_ETHERTYPE_88A8)
 +                              hw_features |= NETIF_F_HW_VLAN_STAG_RX;
 +              } else if (stripping_support->inner !=
 +                         VIRTCHNL_VLAN_UNSUPPORTED &&
 +                         stripping_support->inner & VIRTCHNL_VLAN_TOGGLE) {
 +                      if (stripping_support->inner &
 +                          VIRTCHNL_VLAN_ETHERTYPE_8100)
 +                              hw_features |= NETIF_F_HW_VLAN_CTAG_RX;
 +              }
 +
 +              if (insertion_support->outer != VIRTCHNL_VLAN_UNSUPPORTED &&
 +                  insertion_support->outer & VIRTCHNL_VLAN_TOGGLE) {
 +                      if (insertion_support->outer &
 +                          VIRTCHNL_VLAN_ETHERTYPE_8100)
 +                              hw_features |= NETIF_F_HW_VLAN_CTAG_TX;
 +                      if (insertion_support->outer &
 +                          VIRTCHNL_VLAN_ETHERTYPE_88A8)
 +                              hw_features |= NETIF_F_HW_VLAN_STAG_TX;
 +              } else if (insertion_support->inner &&
 +                         insertion_support->inner & VIRTCHNL_VLAN_TOGGLE) {
 +                      if (insertion_support->inner &
 +                          VIRTCHNL_VLAN_ETHERTYPE_8100)
 +                              hw_features |= NETIF_F_HW_VLAN_CTAG_TX;
 +              }
 +      }
 +
 +      return hw_features;
 +}
 +
 +/**
 + * iavf_get_netdev_vlan_features - get the enabled NETDEV VLAN fetures
 + * @adapter: board private structure
 + *
 + * Depending on whether VIRTHCNL_VF_OFFLOAD_VLAN or VIRTCHNL_VF_OFFLOAD_VLAN_V2
 + * were negotiated determine the VLAN features that are enabled by default.
 + **/
 +static netdev_features_t
 +iavf_get_netdev_vlan_features(struct iavf_adapter *adapter)
 +{
 +      netdev_features_t features = 0;
 +
 +      if (!adapter->vf_res || !adapter->vf_res->vf_cap_flags)
 +              return features;
 +
 +      if (VLAN_ALLOWED(adapter)) {
 +              features |= NETIF_F_HW_VLAN_CTAG_FILTER |
 +                      NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HW_VLAN_CTAG_TX;
 +      } else if (VLAN_V2_ALLOWED(adapter)) {
 +              struct virtchnl_vlan_caps *vlan_v2_caps =
 +                      &adapter->vlan_v2_caps;
 +              struct virtchnl_vlan_supported_caps *filtering_support =
 +                      &vlan_v2_caps->filtering.filtering_support;
 +              struct virtchnl_vlan_supported_caps *stripping_support =
 +                      &vlan_v2_caps->offloads.stripping_support;
 +              struct virtchnl_vlan_supported_caps *insertion_support =
 +                      &vlan_v2_caps->offloads.insertion_support;
 +              u32 ethertype_init;
 +
 +              /* give priority to outer stripping and don't support both outer
 +               * and inner stripping
 +               */
 +              ethertype_init = vlan_v2_caps->offloads.ethertype_init;
 +              if (stripping_support->outer != VIRTCHNL_VLAN_UNSUPPORTED) {
 +                      if (stripping_support->outer &
 +                          VIRTCHNL_VLAN_ETHERTYPE_8100 &&
 +                          ethertype_init & VIRTCHNL_VLAN_ETHERTYPE_8100)
 +                              features |= NETIF_F_HW_VLAN_CTAG_RX;
 +                      else if (stripping_support->outer &
 +                               VIRTCHNL_VLAN_ETHERTYPE_88A8 &&
 +                               ethertype_init & VIRTCHNL_VLAN_ETHERTYPE_88A8)
 +                              features |= NETIF_F_HW_VLAN_STAG_RX;
 +              } else if (stripping_support->inner !=
 +                         VIRTCHNL_VLAN_UNSUPPORTED) {
 +                      if (stripping_support->inner &
 +                          VIRTCHNL_VLAN_ETHERTYPE_8100 &&
 +                          ethertype_init & VIRTCHNL_VLAN_ETHERTYPE_8100)
 +                              features |= NETIF_F_HW_VLAN_CTAG_RX;
 +              }
 +
 +              /* give priority to outer insertion and don't support both outer
 +               * and inner insertion
 +               */
 +              if (insertion_support->outer != VIRTCHNL_VLAN_UNSUPPORTED) {
 +                      if (insertion_support->outer &
 +                          VIRTCHNL_VLAN_ETHERTYPE_8100 &&
 +                          ethertype_init & VIRTCHNL_VLAN_ETHERTYPE_8100)
 +                              features |= NETIF_F_HW_VLAN_CTAG_TX;
 +                      else if (insertion_support->outer &
 +                               VIRTCHNL_VLAN_ETHERTYPE_88A8 &&
 +                               ethertype_init & VIRTCHNL_VLAN_ETHERTYPE_88A8)
 +                              features |= NETIF_F_HW_VLAN_STAG_TX;
 +              } else if (insertion_support->inner !=
 +                         VIRTCHNL_VLAN_UNSUPPORTED) {
 +                      if (insertion_support->inner &
 +                          VIRTCHNL_VLAN_ETHERTYPE_8100 &&
 +                          ethertype_init & VIRTCHNL_VLAN_ETHERTYPE_8100)
 +                              features |= NETIF_F_HW_VLAN_CTAG_TX;
 +              }
 +
 +              /* give priority to outer filtering and don't bother if both
 +               * outer and inner filtering are enabled
 +               */
 +              ethertype_init = vlan_v2_caps->filtering.ethertype_init;
 +              if (filtering_support->outer != VIRTCHNL_VLAN_UNSUPPORTED) {
 +                      if (filtering_support->outer &
 +                          VIRTCHNL_VLAN_ETHERTYPE_8100 &&
 +                          ethertype_init & VIRTCHNL_VLAN_ETHERTYPE_8100)
 +                              features |= NETIF_F_HW_VLAN_CTAG_FILTER;
 +                      if (filtering_support->outer &
 +                          VIRTCHNL_VLAN_ETHERTYPE_88A8 &&
 +                          ethertype_init & VIRTCHNL_VLAN_ETHERTYPE_88A8)
 +                              features |= NETIF_F_HW_VLAN_STAG_FILTER;
 +              } else if (filtering_support->inner !=
 +                         VIRTCHNL_VLAN_UNSUPPORTED) {
 +                      if (filtering_support->inner &
 +                          VIRTCHNL_VLAN_ETHERTYPE_8100 &&
 +                          ethertype_init & VIRTCHNL_VLAN_ETHERTYPE_8100)
 +                              features |= NETIF_F_HW_VLAN_CTAG_FILTER;
 +                      if (filtering_support->inner &
 +                          VIRTCHNL_VLAN_ETHERTYPE_88A8 &&
 +                          ethertype_init & VIRTCHNL_VLAN_ETHERTYPE_88A8)
 +                              features |= NETIF_F_HW_VLAN_STAG_FILTER;
 +              }
 +      }
 +
 +      return features;
 +}
 +
 +#define IAVF_NETDEV_VLAN_FEATURE_ALLOWED(requested, allowed, feature_bit) \
 +      (!(((requested) & (feature_bit)) && \
 +         !((allowed) & (feature_bit))))
 +
 +/**
 + * iavf_fix_netdev_vlan_features - fix NETDEV VLAN features based on support
 + * @adapter: board private structure
 + * @requested_features: stack requested NETDEV features
 + **/
 +static netdev_features_t
 +iavf_fix_netdev_vlan_features(struct iavf_adapter *adapter,
 +                            netdev_features_t requested_features)
 +{
 +      netdev_features_t allowed_features;
 +
 +      allowed_features = iavf_get_netdev_vlan_hw_features(adapter) |
 +              iavf_get_netdev_vlan_features(adapter);
 +
 +      if (!IAVF_NETDEV_VLAN_FEATURE_ALLOWED(requested_features,
 +                                            allowed_features,
 +                                            NETIF_F_HW_VLAN_CTAG_TX))
 +              requested_features &= ~NETIF_F_HW_VLAN_CTAG_TX;
 +
 +      if (!IAVF_NETDEV_VLAN_FEATURE_ALLOWED(requested_features,
 +                                            allowed_features,
 +                                            NETIF_F_HW_VLAN_CTAG_RX))
 +              requested_features &= ~NETIF_F_HW_VLAN_CTAG_RX;
 +
 +      if (!IAVF_NETDEV_VLAN_FEATURE_ALLOWED(requested_features,
 +                                            allowed_features,
 +                                            NETIF_F_HW_VLAN_STAG_TX))
 +              requested_features &= ~NETIF_F_HW_VLAN_STAG_TX;
 +      if (!IAVF_NETDEV_VLAN_FEATURE_ALLOWED(requested_features,
 +                                            allowed_features,
 +                                            NETIF_F_HW_VLAN_STAG_RX))
 +              requested_features &= ~NETIF_F_HW_VLAN_STAG_RX;
 +
 +      if (!IAVF_NETDEV_VLAN_FEATURE_ALLOWED(requested_features,
 +                                            allowed_features,
 +                                            NETIF_F_HW_VLAN_CTAG_FILTER))
 +              requested_features &= ~NETIF_F_HW_VLAN_CTAG_FILTER;
 +
 +      if (!IAVF_NETDEV_VLAN_FEATURE_ALLOWED(requested_features,
 +                                            allowed_features,
 +                                            NETIF_F_HW_VLAN_STAG_FILTER))
 +              requested_features &= ~NETIF_F_HW_VLAN_STAG_FILTER;
 +
 +      if ((requested_features &
 +           (NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HW_VLAN_CTAG_TX)) &&
 +          (requested_features &
 +           (NETIF_F_HW_VLAN_STAG_RX | NETIF_F_HW_VLAN_STAG_TX)) &&
 +          adapter->vlan_v2_caps.offloads.ethertype_match ==
 +          VIRTCHNL_ETHERTYPE_STRIPPING_MATCHES_INSERTION) {
 +              netdev_warn(adapter->netdev, "cannot support CTAG and STAG VLAN stripping and/or insertion simultaneously since CTAG and STAG offloads are mutually exclusive, clearing STAG offload settings\n");
 +              requested_features &= ~(NETIF_F_HW_VLAN_STAG_RX |
 +                                      NETIF_F_HW_VLAN_STAG_TX);
 +      }
 +
 +      return requested_features;
 +}
 +
  /**
   * iavf_fix_features - fix up the netdev feature bits
   * @netdev: our net device
@@@ -4176,7 -3546,13 +4176,7 @@@ static netdev_features_t iavf_fix_featu
  {
        struct iavf_adapter *adapter = netdev_priv(netdev);
  
 -      if (adapter->vf_res &&
 -          !(adapter->vf_res->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_VLAN))
 -              features &= ~(NETIF_F_HW_VLAN_CTAG_TX |
 -                            NETIF_F_HW_VLAN_CTAG_RX |
 -                            NETIF_F_HW_VLAN_CTAG_FILTER);
 -
 -      return features;
 +      return iavf_fix_netdev_vlan_features(adapter, features);
  }
  
  static const struct net_device_ops iavf_netdev_ops = {
@@@ -4228,11 -3604,39 +4228,11 @@@ static int iavf_check_reset_complete(st
  int iavf_process_config(struct iavf_adapter *adapter)
  {
        struct virtchnl_vf_resource *vfres = adapter->vf_res;
 -      int i, num_req_queues = adapter->num_req_queues;
 +      netdev_features_t hw_vlan_features, vlan_features;
        struct net_device *netdev = adapter->netdev;
 -      struct iavf_vsi *vsi = &adapter->vsi;
        netdev_features_t hw_enc_features;
        netdev_features_t hw_features;
  
 -      /* got VF config message back from PF, now we can parse it */
 -      for (i = 0; i < vfres->num_vsis; i++) {
 -              if (vfres->vsi_res[i].vsi_type == VIRTCHNL_VSI_SRIOV)
 -                      adapter->vsi_res = &vfres->vsi_res[i];
 -      }
 -      if (!adapter->vsi_res) {
 -              dev_err(&adapter->pdev->dev, "No LAN VSI found\n");
 -              return -ENODEV;
 -      }
 -
 -      if (num_req_queues &&
 -          num_req_queues > adapter->vsi_res->num_queue_pairs) {
 -              /* Problem.  The PF gave us fewer queues than what we had
 -               * negotiated in our request.  Need a reset to see if we can't
 -               * get back to a working state.
 -               */
 -              dev_err(&adapter->pdev->dev,
 -                      "Requested %d queues, but PF only gave us %d.\n",
 -                      num_req_queues,
 -                      adapter->vsi_res->num_queue_pairs);
 -              adapter->flags |= IAVF_FLAG_REINIT_ITR_NEEDED;
 -              adapter->num_req_queues = adapter->vsi_res->num_queue_pairs;
 -              iavf_schedule_reset(adapter);
 -              return -ENODEV;
 -      }
 -      adapter->num_req_queues = 0;
 -
        hw_enc_features = NETIF_F_SG                    |
                          NETIF_F_IP_CSUM               |
                          NETIF_F_IPV6_CSUM             |
         */
        hw_features = hw_enc_features;
  
 -      /* Enable VLAN features if supported */
 -      if (vfres->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_VLAN)
 -              hw_features |= (NETIF_F_HW_VLAN_CTAG_TX |
 -                              NETIF_F_HW_VLAN_CTAG_RX);
 +      /* get HW VLAN features that can be toggled */
 +      hw_vlan_features = iavf_get_netdev_vlan_hw_features(adapter);
 +
        /* Enable cloud filter if ADQ is supported */
        if (vfres->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_ADQ)
                hw_features |= NETIF_F_HW_TC;
        if (vfres->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_USO)
                hw_features |= NETIF_F_GSO_UDP_L4;
  
 -      netdev->hw_features |= hw_features;
 +      netdev->hw_features |= hw_features | hw_vlan_features;
 +      vlan_features = iavf_get_netdev_vlan_features(adapter);
  
 -      netdev->features |= hw_features;
 +      netdev->features |= hw_features | vlan_features;
  
        if (vfres->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_VLAN)
                netdev->features |= NETIF_F_HW_VLAN_CTAG_FILTER;
                        netdev->features &= ~NETIF_F_GSO;
        }
  
 -      adapter->vsi.id = adapter->vsi_res->vsi_id;
 -
 -      adapter->vsi.back = adapter;
 -      adapter->vsi.base_vector = 1;
 -      adapter->vsi.work_limit = IAVF_DEFAULT_IRQ_WORK;
 -      vsi->netdev = adapter->netdev;
 -      vsi->qs_handle = adapter->vsi_res->qset_handle;
 -      if (vfres->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_RSS_PF) {
 -              adapter->rss_key_size = vfres->rss_key_size;
 -              adapter->rss_lut_size = vfres->rss_lut_size;
 -      } else {
 -              adapter->rss_key_size = IAVF_HKEY_ARRAY_SIZE;
 -              adapter->rss_lut_size = IAVF_HLUT_ARRAY_SIZE;
 -      }
 -
        return 0;
  }
  
@@@ -4582,7 -4001,6 +4582,7 @@@ static void iavf_remove(struct pci_dev 
        if (iavf_lock_timeout(&adapter->crit_lock, 5000))
                dev_warn(&adapter->pdev->dev, "failed to acquire crit_lock in %s\n", __FUNCTION__);
  
 +      dev_info(&adapter->pdev->dev, "Removing device\n");
        /* Shut down all the garbage mashers on the detention level */
        iavf_change_state(adapter, __IAVF_REMOVE);
        adapter->aq_required = 0;
index c6ff656b2476fe795e4d3b5b6297809ee94bb0e3,7068ecb289f310e7271a6fde7e0c038911da3ee9..89b4670062912084fd5d1f7601b75150c0c36387
@@@ -2170,7 -2170,7 +2170,7 @@@ static struct sk_buff *ixgbe_build_skb(
        net_prefetch(xdp->data_meta);
  
        /* build an skb to around the page buffer */
 -      skb = build_skb(xdp->data_hard_start, truesize);
 +      skb = napi_build_skb(xdp->data_hard_start, truesize);
        if (unlikely(!skb))
                return NULL;
  
@@@ -2235,7 -2235,7 +2235,7 @@@ static struct sk_buff *ixgbe_run_xdp(st
                result = IXGBE_XDP_REDIR;
                break;
        default:
 -              bpf_warn_invalid_xdp_action(act);
 +              bpf_warn_invalid_xdp_action(rx_ring->netdev, xdp_prog, act);
                fallthrough;
        case XDP_ABORTED:
  out_failure:
@@@ -3247,8 -3247,8 +3247,8 @@@ static int ixgbe_request_msix_irqs(stru
                /* If Flow Director is enabled, set interrupt affinity */
                if (adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE) {
                        /* assign the mask for this irq */
-                       irq_set_affinity_hint(entry->vector,
-                                             &q_vector->affinity_mask);
+                       irq_update_affinity_hint(entry->vector,
+                                                &q_vector->affinity_mask);
                }
        }
  
  free_queue_irqs:
        while (vector) {
                vector--;
-               irq_set_affinity_hint(adapter->msix_entries[vector].vector,
-                                     NULL);
+               irq_update_affinity_hint(adapter->msix_entries[vector].vector,
+                                        NULL);
                free_irq(adapter->msix_entries[vector].vector,
                         adapter->q_vector[vector]);
        }
@@@ -3398,7 -3398,7 +3398,7 @@@ static void ixgbe_free_irq(struct ixgbe
                        continue;
  
                /* clear the affinity_mask in the IRQ descriptor */
-               irq_set_affinity_hint(entry->vector, NULL);
+               irq_update_affinity_hint(entry->vector, NULL);
  
                free_irq(entry->vector, q_vector);
        }
index 90fec0649ef531df59a3c37fe33b5e05e929dcab,fd7a671eda33ba3407c9518fe8b2e69ef2cc9b74..41807ef552011a0e41b03bbc0c14bc68baabb551
@@@ -7,12 -7,15 +7,12 @@@
  #include <linux/mlx5/driver.h>
  #include "mlx5_core.h"
  #include "mlx5_irq.h"
 +#include "pci_irq.h"
  #include "lib/sf.h"
  #ifdef CONFIG_RFS_ACCEL
  #include <linux/cpu_rmap.h>
  #endif
  
 -#define MLX5_MAX_IRQ_NAME (32)
 -/* max irq_index is 2047, so four chars */
 -#define MLX5_MAX_IRQ_IDX_CHARS (4)
 -
  #define MLX5_SFS_PER_CTRL_IRQ 64
  #define MLX5_IRQ_CTRL_SF_MAX 8
  /* min num of vectors for SFs to be enabled */
@@@ -22,6 -25,7 +22,6 @@@
  #define MLX5_EQ_SHARE_IRQ_MAX_CTRL (UINT_MAX)
  #define MLX5_EQ_SHARE_IRQ_MIN_COMP (1)
  #define MLX5_EQ_SHARE_IRQ_MIN_CTRL (4)
 -#define MLX5_EQ_REFS_PER_IRQ (2)
  
  struct mlx5_irq {
        struct atomic_notifier_head nh;
        int irqn;
  };
  
 -struct mlx5_irq_pool {
 -      char name[MLX5_MAX_IRQ_NAME - MLX5_MAX_IRQ_IDX_CHARS];
 -      struct xa_limit xa_num_irqs;
 -      struct mutex lock; /* sync IRQs creations */
 -      struct xarray irqs;
 -      u32 max_threshold;
 -      u32 min_threshold;
 -      struct mlx5_core_dev *dev;
 -};
 -
  struct mlx5_irq_table {
        struct mlx5_irq_pool *pf_pool;
        struct mlx5_irq_pool *sf_ctrl_pool;
@@@ -129,38 -143,28 +129,38 @@@ static void irq_release(struct mlx5_ir
        struct mlx5_irq_pool *pool = irq->pool;
  
        xa_erase(&pool->irqs, irq->index);
-       /* free_irq requires that affinity and rmap will be cleared
+       /* free_irq requires that affinity_hint and rmap will be cleared
         * before calling it. This is why there is asymmetry with set_rmap
         * which should be called after alloc_irq but before request_irq.
         */
-       irq_set_affinity_hint(irq->irqn, NULL);
+       irq_update_affinity_hint(irq->irqn, NULL);
        free_cpumask_var(irq->mask);
        free_irq(irq->irqn, &irq->nh);
        kfree(irq);
  }
  
 -static void irq_put(struct mlx5_irq *irq)
 +int mlx5_irq_put(struct mlx5_irq *irq)
  {
        struct mlx5_irq_pool *pool = irq->pool;
 +      int ret = 0;
  
        mutex_lock(&pool->lock);
        irq->refcount--;
 -      if (!irq->refcount)
 +      if (!irq->refcount) {
                irq_release(irq);
 +              ret = 1;
 +      }
        mutex_unlock(&pool->lock);
 +      return ret;
 +}
 +
 +int mlx5_irq_read_locked(struct mlx5_irq *irq)
 +{
 +      lockdep_assert_held(&irq->pool->lock);
 +      return irq->refcount;
  }
  
 -static int irq_get_locked(struct mlx5_irq *irq)
 +int mlx5_irq_get_locked(struct mlx5_irq *irq)
  {
        lockdep_assert_held(&irq->pool->lock);
        if (WARN_ON_ONCE(!irq->refcount))
@@@ -174,7 -178,7 +174,7 @@@ static int irq_get(struct mlx5_irq *irq
        int err;
  
        mutex_lock(&irq->pool->lock);
 -      err = irq_get_locked(irq);
 +      err = mlx5_irq_get_locked(irq);
        mutex_unlock(&irq->pool->lock);
        return err;
  }
@@@ -206,8 -210,12 +206,8 @@@ static void irq_set_name(struct mlx5_ir
        snprintf(name, MLX5_MAX_IRQ_NAME, "mlx5_comp%d", vecidx);
  }
  
 -static bool irq_pool_is_sf_pool(struct mlx5_irq_pool *pool)
 -{
 -      return !strncmp("mlx5_sf", pool->name, strlen("mlx5_sf"));
 -}
 -
 -static struct mlx5_irq *irq_request(struct mlx5_irq_pool *pool, int i)
 +struct mlx5_irq *mlx5_irq_alloc(struct mlx5_irq_pool *pool, int i,
 +                              const struct cpumask *affinity)
  {
        struct mlx5_core_dev *dev = pool->dev;
        char name[MLX5_MAX_IRQ_NAME];
        if (!irq)
                return ERR_PTR(-ENOMEM);
        irq->irqn = pci_irq_vector(dev->pdev, i);
 -      if (!irq_pool_is_sf_pool(pool))
 +      if (!mlx5_irq_pool_is_sf_pool(pool))
                irq_set_name(pool, name, i);
        else
                irq_sf_set_name(pool, name, i);
                err = -ENOMEM;
                goto err_cpumask;
        }
-               irq_set_affinity_hint(irq->irqn, irq->mask);
 +      if (affinity) {
 +              cpumask_copy(irq->mask, affinity);
++              irq_set_affinity_and_hint(irq->irqn, irq->mask);
 +      }
        irq->pool = pool;
        irq->refcount = 1;
        irq->index = i;
        }
        return irq;
  err_xa:
-       irq_set_affinity_hint(irq->irqn, NULL);
++      irq_update_affinity_hint(irq->irqn, NULL);
        free_cpumask_var(irq->mask);
  err_cpumask:
        free_irq(irq->irqn, &irq->nh);
@@@ -272,7 -275,7 +272,7 @@@ int mlx5_irq_attach_nb(struct mlx5_irq 
                return -ENOENT;
        ret = atomic_notifier_chain_register(&irq->nh, nb);
        if (ret)
 -              irq_put(irq);
 +              mlx5_irq_put(irq);
        return ret;
  }
  
@@@ -281,7 -284,7 +281,7 @@@ int mlx5_irq_detach_nb(struct mlx5_irq 
        int err = 0;
  
        err = atomic_notifier_chain_unregister(&irq->nh, nb);
 -      irq_put(irq);
 +      mlx5_irq_put(irq);
        return err;
  }
  
@@@ -297,121 -300,131 +297,121 @@@ int mlx5_irq_get_index(struct mlx5_irq 
  
  /* irq_pool API */
  
 -/* creating an irq from irq_pool */
 -static struct mlx5_irq *irq_pool_create_irq(struct mlx5_irq_pool *pool,
 -                                          struct cpumask *affinity)
 +/* requesting an irq from a given pool according to given index */
 +static struct mlx5_irq *
 +irq_pool_request_vector(struct mlx5_irq_pool *pool, int vecidx,
 +                      struct cpumask *affinity)
  {
        struct mlx5_irq *irq;
 -      u32 irq_index;
 -      int err;
  
 -      err = xa_alloc(&pool->irqs, &irq_index, NULL, pool->xa_num_irqs,
 -                     GFP_KERNEL);
 -      if (err)
 -              return ERR_PTR(err);
 -      irq = irq_request(pool, irq_index);
 -      if (IS_ERR(irq))
 -              return irq;
 -      cpumask_copy(irq->mask, affinity);
 -      irq_set_affinity_and_hint(irq->irqn, irq->mask);
 +      mutex_lock(&pool->lock);
 +      irq = xa_load(&pool->irqs, vecidx);
 +      if (irq) {
 +              mlx5_irq_get_locked(irq);
 +              goto unlock;
 +      }
 +      irq = mlx5_irq_alloc(pool, vecidx, affinity);
 +unlock:
 +      mutex_unlock(&pool->lock);
        return irq;
  }
  
 -/* looking for the irq with the smallest refcount and the same affinity */
 -static struct mlx5_irq *irq_pool_find_least_loaded(struct mlx5_irq_pool *pool,
 -                                                 struct cpumask *affinity)
 +static struct mlx5_irq_pool *sf_ctrl_irq_pool_get(struct mlx5_irq_table *irq_table)
  {
 -      int start = pool->xa_num_irqs.min;
 -      int end = pool->xa_num_irqs.max;
 -      struct mlx5_irq *irq = NULL;
 -      struct mlx5_irq *iter;
 -      unsigned long index;
 +      return irq_table->sf_ctrl_pool;
 +}
  
 -      lockdep_assert_held(&pool->lock);
 -      xa_for_each_range(&pool->irqs, index, iter, start, end) {
 -              if (!cpumask_equal(iter->mask, affinity))
 -                      continue;
 -              if (iter->refcount < pool->min_threshold)
 -                      return iter;
 -              if (!irq || iter->refcount < irq->refcount)
 -                      irq = iter;
 -      }
 -      return irq;
 +static struct mlx5_irq_pool *sf_irq_pool_get(struct mlx5_irq_table *irq_table)
 +{
 +      return irq_table->sf_comp_pool;
  }
  
 -/* requesting an irq from a given pool according to given affinity */
 -static struct mlx5_irq *irq_pool_request_affinity(struct mlx5_irq_pool *pool,
 -                                                struct cpumask *affinity)
 +struct mlx5_irq_pool *mlx5_irq_pool_get(struct mlx5_core_dev *dev)
  {
 -      struct mlx5_irq *least_loaded_irq, *new_irq;
 +      struct mlx5_irq_table *irq_table = mlx5_irq_table_get(dev);
 +      struct mlx5_irq_pool *pool = NULL;
  
 -      mutex_lock(&pool->lock);
 -      least_loaded_irq = irq_pool_find_least_loaded(pool, affinity);
 -      if (least_loaded_irq &&
 -          least_loaded_irq->refcount < pool->min_threshold)
 -              goto out;
 -      new_irq = irq_pool_create_irq(pool, affinity);
 -      if (IS_ERR(new_irq)) {
 -              if (!least_loaded_irq) {
 -                      mlx5_core_err(pool->dev, "Didn't find a matching IRQ. err = %ld\n",
 -                                    PTR_ERR(new_irq));
 -                      mutex_unlock(&pool->lock);
 -                      return new_irq;
 -              }
 -              /* We failed to create a new IRQ for the requested affinity,
 -               * sharing existing IRQ.
 -               */
 -              goto out;
 -      }
 -      least_loaded_irq = new_irq;
 -      goto unlock;
 -out:
 -      irq_get_locked(least_loaded_irq);
 -      if (least_loaded_irq->refcount > pool->max_threshold)
 -              mlx5_core_dbg(pool->dev, "IRQ %u overloaded, pool_name: %s, %u EQs on this irq\n",
 -                            least_loaded_irq->irqn, pool->name,
 -                            least_loaded_irq->refcount / MLX5_EQ_REFS_PER_IRQ);
 -unlock:
 -      mutex_unlock(&pool->lock);
 -      return least_loaded_irq;
 +      if (mlx5_core_is_sf(dev))
 +              pool = sf_irq_pool_get(irq_table);
 +
 +      /* In some configs, there won't be a pool of SFs IRQs. Hence, returning
 +       * the PF IRQs pool in case the SF pool doesn't exist.
 +       */
 +      return pool ? pool : irq_table->pf_pool;
  }
  
 -/* requesting an irq from a given pool according to given index */
 -static struct mlx5_irq *
 -irq_pool_request_vector(struct mlx5_irq_pool *pool, int vecidx,
 -                      struct cpumask *affinity)
 +static struct mlx5_irq_pool *ctrl_irq_pool_get(struct mlx5_core_dev *dev)
  {
 -      struct mlx5_irq *irq;
 +      struct mlx5_irq_table *irq_table = mlx5_irq_table_get(dev);
 +      struct mlx5_irq_pool *pool = NULL;
  
 -      mutex_lock(&pool->lock);
 -      irq = xa_load(&pool->irqs, vecidx);
 -      if (irq) {
 -              irq_get_locked(irq);
 -              goto unlock;
 +      if (mlx5_core_is_sf(dev))
 +              pool = sf_ctrl_irq_pool_get(irq_table);
 +
 +      /* In some configs, there won't be a pool of SFs IRQs. Hence, returning
 +       * the PF IRQs pool in case the SF pool doesn't exist.
 +       */
 +      return pool ? pool : irq_table->pf_pool;
 +}
 +
 +/**
 + * mlx5_irqs_release - release one or more IRQs back to the system.
 + * @irqs: IRQs to be released.
 + * @nirqs: number of IRQs to be released.
 + */
 +static void mlx5_irqs_release(struct mlx5_irq **irqs, int nirqs)
 +{
 +      int i;
 +
 +      for (i = 0; i < nirqs; i++) {
 +              synchronize_irq(irqs[i]->irqn);
 +              mlx5_irq_put(irqs[i]);
        }
 -      irq = irq_request(pool, vecidx);
 -      if (IS_ERR(irq) || !affinity)
 -              goto unlock;
 -      cpumask_copy(irq->mask, affinity);
 -      if (!irq_pool_is_sf_pool(pool) && !pool->xa_num_irqs.max &&
 -          cpumask_empty(irq->mask))
 -              cpumask_set_cpu(cpumask_first(cpu_online_mask), irq->mask);
 -      irq_set_affinity_and_hint(irq->irqn, irq->mask);
 -unlock:
 -      mutex_unlock(&pool->lock);
 -      return irq;
  }
  
 -static struct mlx5_irq_pool *find_sf_irq_pool(struct mlx5_irq_table *irq_table,
 -                                            int i, struct cpumask *affinity)
 +/**
 + * mlx5_ctrl_irq_release - release a ctrl IRQ back to the system.
 + * @ctrl_irq: ctrl IRQ to be released.
 + */
 +void mlx5_ctrl_irq_release(struct mlx5_irq *ctrl_irq)
  {
 -      if (cpumask_empty(affinity) && i == MLX5_IRQ_EQ_CTRL)
 -              return irq_table->sf_ctrl_pool;
 -      return irq_table->sf_comp_pool;
 +      mlx5_irqs_release(&ctrl_irq, 1);
  }
  
  /**
 - * mlx5_irq_release - release an IRQ back to the system.
 - * @irq: irq to be released.
 + * mlx5_ctrl_irq_request - request a ctrl IRQ for mlx5 device.
 + * @dev: mlx5 device that requesting the IRQ.
 + *
 + * This function returns a pointer to IRQ, or ERR_PTR in case of error.
   */
 -void mlx5_irq_release(struct mlx5_irq *irq)
 +struct mlx5_irq *mlx5_ctrl_irq_request(struct mlx5_core_dev *dev)
  {
 -      synchronize_irq(irq->irqn);
 -      irq_put(irq);
 +      struct mlx5_irq_pool *pool = ctrl_irq_pool_get(dev);
 +      cpumask_var_t req_mask;
 +      struct mlx5_irq *irq;
 +
 +      if (!zalloc_cpumask_var(&req_mask, GFP_KERNEL))
 +              return ERR_PTR(-ENOMEM);
 +      cpumask_copy(req_mask, cpu_online_mask);
 +      if (!mlx5_irq_pool_is_sf_pool(pool)) {
 +              /* In case we are allocating a control IRQ for PF/VF */
 +              if (!pool->xa_num_irqs.max) {
 +                      cpumask_clear(req_mask);
 +                      /* In case we only have a single IRQ for PF/VF */
 +                      cpumask_set_cpu(cpumask_first(cpu_online_mask), req_mask);
 +              }
 +              /* Allocate the IRQ in the last index of the pool */
 +              irq = irq_pool_request_vector(pool, pool->xa_num_irqs.max, req_mask);
 +      } else {
 +              irq = mlx5_irq_affinity_request(pool, req_mask);
 +      }
 +
 +      free_cpumask_var(req_mask);
 +      return irq;
  }
  
  /**
 - * mlx5_irq_request - request an IRQ for mlx5 device.
 + * mlx5_irq_request - request an IRQ for mlx5 PF/VF device.
   * @dev: mlx5 device that requesting the IRQ.
   * @vecidx: vector index of the IRQ. This argument is ignore if affinity is
   * provided.
@@@ -426,8 -439,23 +426,8 @@@ struct mlx5_irq *mlx5_irq_request(struc
        struct mlx5_irq_pool *pool;
        struct mlx5_irq *irq;
  
 -      if (mlx5_core_is_sf(dev)) {
 -              pool = find_sf_irq_pool(irq_table, vecidx, affinity);
 -              if (!pool)
 -                      /* we don't have IRQs for SFs, using the PF IRQs */
 -                      goto pf_irq;
 -              if (cpumask_empty(affinity) && !strcmp(pool->name, "mlx5_sf_comp"))
 -                      /* In case an SF user request IRQ with vecidx */
 -                      irq = irq_pool_request_vector(pool, vecidx, NULL);
 -              else
 -                      irq = irq_pool_request_affinity(pool, affinity);
 -              goto out;
 -      }
 -pf_irq:
        pool = irq_table->pf_pool;
 -      vecidx = (vecidx == MLX5_IRQ_EQ_CTRL) ? pool->xa_num_irqs.max : vecidx;
        irq = irq_pool_request_vector(pool, vecidx, affinity);
 -out:
        if (IS_ERR(irq))
                return irq;
        mlx5_core_dbg(dev, "irq %u mapped to cpu %*pbl, %u EQs on this irq\n",
        return irq;
  }
  
 +/**
 + * mlx5_irqs_release_vectors - release one or more IRQs back to the system.
 + * @irqs: IRQs to be released.
 + * @nirqs: number of IRQs to be released.
 + */
 +void mlx5_irqs_release_vectors(struct mlx5_irq **irqs, int nirqs)
 +{
 +      mlx5_irqs_release(irqs, nirqs);
 +}
 +
 +/**
 + * mlx5_irqs_request_vectors - request one or more IRQs for mlx5 device.
 + * @dev: mlx5 device that is requesting the IRQs.
 + * @cpus: CPUs array for binding the IRQs
 + * @nirqs: number of IRQs to request.
 + * @irqs: an output array of IRQs pointers.
 + *
 + * Each IRQ is bound to at most 1 CPU.
 + * This function is requests nirqs IRQs, starting from @vecidx.
 + *
 + * This function returns the number of IRQs requested, (which might be smaller than
 + * @nirqs), if successful, or a negative error code in case of an error.
 + */
 +int mlx5_irqs_request_vectors(struct mlx5_core_dev *dev, u16 *cpus, int nirqs,
 +                            struct mlx5_irq **irqs)
 +{
 +      cpumask_var_t req_mask;
 +      struct mlx5_irq *irq;
 +      int i;
 +
 +      if (!zalloc_cpumask_var(&req_mask, GFP_KERNEL))
 +              return -ENOMEM;
 +      for (i = 0; i < nirqs; i++) {
 +              cpumask_set_cpu(cpus[i], req_mask);
 +              irq = mlx5_irq_request(dev, i, req_mask);
 +              if (IS_ERR(irq))
 +                      break;
 +              cpumask_clear(req_mask);
 +              irqs[i] = irq;
 +      }
 +
 +      free_cpumask_var(req_mask);
 +      return i ? i : PTR_ERR(irq);
 +}
 +
  static struct mlx5_irq_pool *
  irq_pool_alloc(struct mlx5_core_dev *dev, int start, int size, char *name,
               u32 min_threshold, u32 max_threshold)
        pool->xa_num_irqs.max = start + size - 1;
        if (name)
                snprintf(pool->name, MLX5_MAX_IRQ_NAME - MLX5_MAX_IRQ_IDX_CHARS,
 -                       name);
 +                       "%s", name);
        pool->min_threshold = min_threshold * MLX5_EQ_REFS_PER_IRQ;
        pool->max_threshold = max_threshold * MLX5_EQ_REFS_PER_IRQ;
        mlx5_core_dbg(dev, "pool->name = %s, pool->size = %d, pool->start = %d",
@@@ -517,7 -500,6 +517,7 @@@ static void irq_pool_free(struct mlx5_i
                irq_release(irq);
        xa_destroy(&pool->irqs);
        mutex_destroy(&pool->lock);
 +      kfree(pool->irqs_per_cpu);
        kvfree(pool);
  }
  
@@@ -565,17 -547,7 +565,17 @@@ static int irq_pools_init(struct mlx5_c
                err = PTR_ERR(table->sf_comp_pool);
                goto err_sf_ctrl;
        }
 +
 +      table->sf_comp_pool->irqs_per_cpu = kcalloc(nr_cpu_ids, sizeof(u16), GFP_KERNEL);
 +      if (!table->sf_comp_pool->irqs_per_cpu) {
 +              err = -ENOMEM;
 +              goto err_irqs_per_cpu;
 +      }
 +
        return 0;
 +
 +err_irqs_per_cpu:
 +      irq_pool_free(table->sf_comp_pool);
  err_sf_ctrl:
        irq_pool_free(table->sf_ctrl_pool);
  err_pf: