The promiscuous and all-multicast settings persist in hardware across
a port stop/start and are only cleared by a VF reset. Despite this,
the ethdev start path re-applied them on every `dev_start` through the
config restore logic. Together with the driver's own restore after a
reset, a reset followed by a start reprogrammed them twice and issued
redundant requests to the PF.

Implement the `get_restore_flags` callback to clear
`RTE_ETH_RESTORE_PROMISC` and `RTE_ETH_RESTORE_ALLMULTI` so ethdev
skips them on start; the driver restores them only after a VF reset.
A queue reconfiguration in `iavf_dev_configure` also triggers a reset,
so the states are re-applied there too, except during reset recovery
where the reset handler already restores them once.

Signed-off-by: Ciara Loftus <[email protected]>
---
 drivers/net/intel/iavf/iavf_ethdev.c | 34 ++++++++++++++++++++++++++++
 1 file changed, 34 insertions(+)

diff --git a/drivers/net/intel/iavf/iavf_ethdev.c 
b/drivers/net/intel/iavf/iavf_ethdev.c
index 829573983a..183d986831 100644
--- a/drivers/net/intel/iavf/iavf_ethdev.c
+++ b/drivers/net/intel/iavf/iavf_ethdev.c
@@ -163,6 +163,9 @@ static int iavf_set_mc_addr_list(struct rte_eth_dev *dev,
                        struct rte_ether_addr *mc_addrs,
                        uint32_t mc_addrs_num);
 static int iavf_tm_ops_get(struct rte_eth_dev *dev __rte_unused, void *arg);
+static uint64_t iavf_get_restore_flags(struct rte_eth_dev *dev,
+                                      enum rte_eth_dev_operation op);
+static int iavf_post_reset_reconfig(struct rte_eth_dev *dev);
 
 static const struct rte_pci_id pci_id_iavf_map[] = {
        { RTE_PCI_DEVICE(IAVF_INTEL_VENDOR_ID, IAVF_DEV_ID_ADAPTIVE_VF) },
@@ -262,6 +265,7 @@ static const struct eth_dev_ops iavf_eth_dev_ops = {
        .tx_done_cleanup            = iavf_dev_tx_done_cleanup,
        .get_monitor_addr           = iavf_get_monitor_addr,
        .tm_ops_get                 = iavf_tm_ops_get,
+       .get_restore_flags          = iavf_get_restore_flags,
 };
 
 static int
@@ -282,6 +286,19 @@ iavf_tm_ops_get(struct rte_eth_dev *dev,
        return 0;
 }
 
+static uint64_t
+iavf_get_restore_flags(__rte_unused struct rte_eth_dev *dev,
+                      __rte_unused enum rte_eth_dev_operation op)
+{
+       /*
+        * The unicast and multicast promiscuous settings persist across a
+        * stop/start; they are only cleared by a VF reset, which the driver
+        * restores itself. So ethdev does not need to restore them on start.
+        */
+       return RTE_ETH_RESTORE_ALL & ~(RTE_ETH_RESTORE_PROMISC |
+                                      RTE_ETH_RESTORE_ALLMULTI);
+}
+
 __rte_unused
 static int
 iavf_vfr_inprogress(struct iavf_hw *hw)
@@ -673,6 +690,7 @@ iavf_dev_configure(struct rte_eth_dev *dev)
        struct iavf_info *vf =  IAVF_DEV_PRIVATE_TO_VF(ad);
        uint16_t num_queue_pairs = RTE_MAX(dev->data->nb_rx_queues,
                dev->data->nb_tx_queues);
+       bool reset_done = false;
        int ret;
 
        if (ad->closed)
@@ -702,6 +720,7 @@ iavf_dev_configure(struct rte_eth_dev *dev)
                ret = iavf_queues_req_reset(dev, num_queue_pairs);
                if (ret)
                        return ret;
+               reset_done = true;
 
                ret = iavf_get_max_rss_queue_region(ad);
                if (ret) {
@@ -720,6 +739,7 @@ iavf_dev_configure(struct rte_eth_dev *dev)
                        ret = iavf_queues_req_reset(dev, num_queue_pairs);
                        if (ret)
                                return ret;
+                       reset_done = true;
 
                        vf->lv_enabled = false;
                }
@@ -735,6 +755,20 @@ iavf_dev_configure(struct rte_eth_dev *dev)
                        return -1;
                }
        }
+
+       /*
+        * A queue reconfiguration above triggers a VF reset, which clears the
+        * promiscuous and all-multicast settings in hardware. Re-apply the
+        * pre-reset states here, unless this configure is itself part of reset
+        * recovery, in which case the reset handler restores them once at the
+        * end (avoiding a double restore).
+        */
+       if (reset_done && !vf->in_reset_recovery) {
+               ret = iavf_post_reset_reconfig(dev);
+               if (ret)
+                       return ret;
+       }
+
        return 0;
 }
 
-- 
2.43.0

Reply via email to