> Subject: [PATCH 2/5] net/iavf: defer device start when PF VSI not ready
> 
> During reset recovery iavf_dev_start() might fail (typically -EIO
> from VIRTCHNL_OP_CONFIG_VSI_QUEUES) because the PF VSI is not yet
> active, leaving the VF down and requiring manual intervention
> to recover.
> 
> Added a start_pending flag: when device start fails during recovery,
> defer it instead of erroring out and resume it from newly added
> iavf_resume_pending_start() on the next link-up event, so the
> VF comes back automatically.

It sounds like a fix, can you add a Fixes tag?

> 
> Signed-off-by: Anurag Mandal <[email protected]>
> ---
>  drivers/net/intel/iavf/iavf.h        |  2 +
>  drivers/net/intel/iavf/iavf_ethdev.c | 56 ++++++++++++++++++++++++++--
>  drivers/net/intel/iavf/iavf_vchnl.c  | 16 +++++++-
>  3 files changed, 69 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/net/intel/iavf/iavf.h b/drivers/net/intel/iavf/iavf.h
> index 293adaf6c9..e76c3bb410 100644
> --- a/drivers/net/intel/iavf/iavf.h
> +++ b/drivers/net/intel/iavf/iavf.h
> @@ -293,6 +293,7 @@ struct iavf_info {
>       bool in_reset_recovery;
>       bool reset_pending;
>       bool pf_reset_in_progress;
> +     bool start_pending;
> 
>       uint32_t ptp_caps;
>       rte_spinlock_t phc_time_aq_lock;
> @@ -533,4 +534,5 @@ void iavf_handle_hw_reset(struct rte_eth_dev *dev,
> bool vf_initiated_reset);
>  void iavf_set_no_poll(struct iavf_adapter *adapter, bool link_change);
>  bool is_iavf_supported(struct rte_eth_dev *dev);
>  void iavf_hash_uninit(struct iavf_adapter *ad);
> +void iavf_resume_pending_start(struct rte_eth_dev *dev);
>  #endif /* _IAVF_ETHDEV_H_ */
> diff --git a/drivers/net/intel/iavf/iavf_ethdev.c
> b/drivers/net/intel/iavf/iavf_ethdev.c
> index e475b64971..87b826c873 100644
> --- a/drivers/net/intel/iavf/iavf_ethdev.c
> +++ b/drivers/net/intel/iavf/iavf_ethdev.c
> @@ -1093,6 +1093,9 @@ iavf_dev_start(struct rte_eth_dev *dev)
> 
>       iavf_phc_sync_alarm_start(dev);
> 
> +     /* An explicit start supersedes any pending deferred start */
> +     vf->start_pending = false;
> +
>       return 0;
> 
>  error:
> @@ -1131,6 +1134,9 @@ iavf_dev_stop(struct rte_eth_dev *dev)
>       adapter->stopped = 1;
>       dev->data->dev_started = 0;
> 
> +     /* An explicit stop cancels any pending deferred start */
> +     vf->start_pending = false;
> +
>       return 0;
>  }
> 
> @@ -3425,6 +3431,7 @@ iavf_handle_hw_reset(struct rte_eth_dev *dev,
> bool vf_initiated_reset)
> 
>       vf->in_reset_recovery = true;
>       vf->pf_reset_in_progress = !vf_initiated_reset;
> +     vf->start_pending = false;
>       iavf_set_no_poll(adapter, false);
> 
>       /* Call the pre reset callback */
> @@ -3445,10 +3452,17 @@ iavf_handle_hw_reset(struct rte_eth_dev *dev,
> bool vf_initiated_reset)
>       if (!vf_initiated_reset || restart_device) {
>               /* start the device */
>               ret = iavf_dev_start(dev);
> -             if (ret)
> -                     goto error;
> -
> -             dev->data->dev_started = 1;
> +             if (ret == 0) {
> +                     dev->data->dev_started = 1;
> +             } else {
> +                     PMD_DRV_LOG(WARNING,
> +                                 "dev_start failed during reset recovery
> (rc=%d);"
> +                                 "deferring to next link-up event",
> +                                 ret);
> +                     vf->start_pending = true;
> +                     dev->data->dev_started = 0;
> +                     ret = 0;
> +             }
>       }
> 
>       /* Restore settings after the reset */
> @@ -3662,6 +3676,40 @@ bool is_iavf_supported(struct rte_eth_dev *dev)
>       return !strcmp(dev->device->driver->name,
> rte_iavf_pmd.driver.name);
>  }
> 
> +void
> +iavf_resume_pending_start(struct rte_eth_dev *dev)
> +{
> +     struct iavf_info *vf = IAVF_DEV_PRIVATE_TO_VF(dev->data-
> >dev_private);
> +     int ret;
> +
> +     if (!vf->start_pending)
> +             return;
> +     /*
> +      * If the application has already (re)started the port itself, the
> +      * deferred start is stale, the application's action is honoured
> +      * and resume pending is dropped to avoid starting an
> +      * already-running port a second time.
> +      */
> +     if (dev->data->dev_started) {
> +             vf->start_pending = false;
> +             return;
> +     }
> +
> +     if (!vf->link_up)
> +             return;
> +
> +     PMD_DRV_LOG(DEBUG, "PF link back up; resuming deferred
> dev_start");
> +     ret = iavf_dev_start(dev);

This call to iavf_dev_start could result in another nested call to
iavf_resume_pending_start which would be problematic.
iavf_dev_start polls the ARQ eg.

iavf_dev_start -> iavf_configure_queues -> iavf_execute_vf_cmd_safe ->
iavf_wait_for_msg -> iavf_read_msg_from_pf -> iavf_clean_arq_element

If another LSC happens during this time, you could enter
iavf_handle_link_change_event again and end up calling
iavf_resume_pending_start again. It can maybe be prevented by clearing the
pending flag at the beginning of iavf_resume_pending_start and setting it
again if the start fails.

> +     if (ret == 0) {
> +             dev->data->dev_started = 1;
> +             vf->start_pending = false;
> +     } else {
> +             PMD_DRV_LOG(ERR,
> +                         "deferred dev_start failed (ret=%d); will retry on
> next link-up",
> +                         ret);
> +     }
> +}
> +
>  RTE_PMD_REGISTER_PCI(net_iavf, rte_iavf_pmd);
>  RTE_PMD_REGISTER_PCI_TABLE(net_iavf, pci_id_iavf_map);
>  RTE_PMD_REGISTER_KMOD_DEP(net_iavf, "* igb_uio | vfio-pci");
> diff --git a/drivers/net/intel/iavf/iavf_vchnl.c
> b/drivers/net/intel/iavf/iavf_vchnl.c
> index 56918ebcc1..8e102b02aa 100644
> --- a/drivers/net/intel/iavf/iavf_vchnl.c
> +++ b/drivers/net/intel/iavf/iavf_vchnl.c
> @@ -260,7 +260,7 @@ iavf_handle_link_change_event(struct rte_eth_dev
> *dev,
>        * (link is down or a VF reset is in progress); the watchdog drives
>        * auto-reset recovery, so it must remain armed in those cases.
>        */
> -     if (vf->link_up && !vf->vf_reset)
> +     if (vf->link_up && !vf->vf_reset && !vf->in_reset_recovery)

Is this change relevant to the rest of this patch?

>               iavf_dev_watchdog_disable(adapter);
>       else
>               iavf_dev_watchdog_enable(adapter);
> @@ -271,6 +271,20 @@ iavf_handle_link_change_event(struct rte_eth_dev
> *dev,
>                           adapter->no_poll ? "on" : "off");
>       }
> 
> +     /*
> +      * Resume a deferred dev_start.
> +      * iavf_handle_hw_reset() sets vf->start_pending when
> +      * reset recovery completed dev_init() but iavf_dev_start()
> +      * itself failed (typically -EIO from
> VIRTCHNL_OP_CONFIG_VSI_QUEUES
> +      * when the PF VSI was inactive).
> +      * A link-up event implies the PF VSI is active again, so retry now.
> +      * Run before the LSC event post so the port is ready to accept Tx
> +      * by the time the app's link-up callback fires; no_poll has already
> +      * been cleared above so bursts go through as soon as
> +      * dev_start sets dev_started=1.
> +      */

I think this comment is verbose, consider shortening it.

> +     iavf_resume_pending_start(dev);
> +
>       iavf_dev_event_post(dev, RTE_ETH_EVENT_INTR_LSC, NULL, 0);
> 
>       PMD_DRV_LOG(INFO, "Link status update:%s",
> --
> 2.34.1

Reply via email to