lkml.org 
[lkml]   [2020]   [Dec]   [1]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 5.4 62/98] i40e: Fix removing driver while bare-metal VFs pass traffic
    Date
    From: Sylwester Dziedziuch <sylwesterx.dziedziuch@intel.com>

    [ Upstream commit 2980cbd4dce7b1e9bf57df3ced43a7b184986f50 ]

    Prevent VFs from resetting when PF driver is being unloaded:
    - introduce new pf state: __I40E_VF_RESETS_DISABLED;
    - check if pf state has __I40E_VF_RESETS_DISABLED state set,
    if so, disable any further VFLR event notifications;
    - when i40e_remove (rmmod i40e) is called, disable any resets on
    the VFs;

    Previously if there were bare-metal VFs passing traffic and PF
    driver was removed, there was a possibility of VFs triggering a Tx
    timeout right before iavf_remove. This was causing iavf_close to
    not be called because there is a check in the beginning of iavf_remove
    that bails out early if adapter->state < IAVF_DOWN_PENDING. This
    makes it so some resources do not get cleaned up.

    Fixes: 6a9ddb36eeb8 ("i40e: disable IOV before freeing resources")
    Signed-off-by: Slawomir Laba <slawomirx.laba@intel.com>
    Signed-off-by: Brett Creeley <brett.creeley@intel.com>
    Signed-off-by: Sylwester Dziedziuch <sylwesterx.dziedziuch@intel.com>
    Tested-by: Konrad Jankowski <konrad0.jankowski@intel.com>
    Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
    Link: https://lore.kernel.org/r/20201120180640.3654474-1-anthony.l.nguyen@intel.com
    Signed-off-by: Jakub Kicinski <kuba@kernel.org>
    Signed-off-by: Sasha Levin <sashal@kernel.org>
    ---
    drivers/net/ethernet/intel/i40e/i40e.h | 1 +
    drivers/net/ethernet/intel/i40e/i40e_main.c | 22 +++++++++++-----
    .../ethernet/intel/i40e/i40e_virtchnl_pf.c | 26 +++++++++++--------
    3 files changed, 31 insertions(+), 18 deletions(-)

    diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h
    index 401304d4d5536..cfe99bae8e362 100644
    --- a/drivers/net/ethernet/intel/i40e/i40e.h
    +++ b/drivers/net/ethernet/intel/i40e/i40e.h
    @@ -150,6 +150,7 @@ enum i40e_state_t {
    __I40E_CLIENT_RESET,
    __I40E_VIRTCHNL_OP_PENDING,
    __I40E_RECOVERY_MODE,
    + __I40E_VF_RESETS_DISABLED, /* disable resets during i40e_remove */
    /* This must be last as it determines the size of the BITMAP */
    __I40E_STATE_SIZE__,
    };
    diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c
    index b3c3911adfc2e..2b4327416457d 100644
    --- a/drivers/net/ethernet/intel/i40e/i40e_main.c
    +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c
    @@ -3988,8 +3988,16 @@ static irqreturn_t i40e_intr(int irq, void *data)
    }

    if (icr0 & I40E_PFINT_ICR0_VFLR_MASK) {
    - ena_mask &= ~I40E_PFINT_ICR0_ENA_VFLR_MASK;
    - set_bit(__I40E_VFLR_EVENT_PENDING, pf->state);
    + /* disable any further VFLR event notifications */
    + if (test_bit(__I40E_VF_RESETS_DISABLED, pf->state)) {
    + u32 reg = rd32(hw, I40E_PFINT_ICR0_ENA);
    +
    + reg &= ~I40E_PFINT_ICR0_VFLR_MASK;
    + wr32(hw, I40E_PFINT_ICR0_ENA, reg);
    + } else {
    + ena_mask &= ~I40E_PFINT_ICR0_ENA_VFLR_MASK;
    + set_bit(__I40E_VFLR_EVENT_PENDING, pf->state);
    + }
    }

    if (icr0 & I40E_PFINT_ICR0_GRST_MASK) {
    @@ -15345,6 +15353,11 @@ static void i40e_remove(struct pci_dev *pdev)
    while (test_bit(__I40E_RESET_RECOVERY_PENDING, pf->state))
    usleep_range(1000, 2000);

    + if (pf->flags & I40E_FLAG_SRIOV_ENABLED) {
    + set_bit(__I40E_VF_RESETS_DISABLED, pf->state);
    + i40e_free_vfs(pf);
    + pf->flags &= ~I40E_FLAG_SRIOV_ENABLED;
    + }
    /* no more scheduling of any task */
    set_bit(__I40E_SUSPENDED, pf->state);
    set_bit(__I40E_DOWN, pf->state);
    @@ -15371,11 +15384,6 @@ static void i40e_remove(struct pci_dev *pdev)
    */
    i40e_notify_client_of_netdev_close(pf->vsi[pf->lan_vsi], false);

    - if (pf->flags & I40E_FLAG_SRIOV_ENABLED) {
    - i40e_free_vfs(pf);
    - pf->flags &= ~I40E_FLAG_SRIOV_ENABLED;
    - }
    -
    i40e_fdir_teardown(pf);

    /* If there is a switch structure or any orphans, remove them.
    diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
    index 38042d610f82c..09ff3f335ffa6 100644
    --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
    +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
    @@ -1335,7 +1335,8 @@ static void i40e_cleanup_reset_vf(struct i40e_vf *vf)
    * @vf: pointer to the VF structure
    * @flr: VFLR was issued or not
    *
    - * Returns true if the VF is reset, false otherwise.
    + * Returns true if the VF is in reset, resets successfully, or resets
    + * are disabled and false otherwise.
    **/
    bool i40e_reset_vf(struct i40e_vf *vf, bool flr)
    {
    @@ -1345,11 +1346,14 @@ bool i40e_reset_vf(struct i40e_vf *vf, bool flr)
    u32 reg;
    int i;

    + if (test_bit(__I40E_VF_RESETS_DISABLED, pf->state))
    + return true;
    +
    /* If the VFs have been disabled, this means something else is
    * resetting the VF, so we shouldn't continue.
    */
    if (test_and_set_bit(__I40E_VF_DISABLE, pf->state))
    - return false;
    + return true;

    i40e_trigger_vf_reset(vf, flr);

    @@ -1513,6 +1517,15 @@ void i40e_free_vfs(struct i40e_pf *pf)

    i40e_notify_client_of_vf_enable(pf, 0);

    + /* Disable IOV before freeing resources. This lets any VF drivers
    + * running in the host get themselves cleaned up before we yank
    + * the carpet out from underneath their feet.
    + */
    + if (!pci_vfs_assigned(pf->pdev))
    + pci_disable_sriov(pf->pdev);
    + else
    + dev_warn(&pf->pdev->dev, "VFs are assigned - not disabling SR-IOV\n");
    +
    /* Amortize wait time by stopping all VFs at the same time */
    for (i = 0; i < pf->num_alloc_vfs; i++) {
    if (test_bit(I40E_VF_STATE_INIT, &pf->vf[i].vf_states))
    @@ -1528,15 +1541,6 @@ void i40e_free_vfs(struct i40e_pf *pf)
    i40e_vsi_wait_queues_disabled(pf->vsi[pf->vf[i].lan_vsi_idx]);
    }

    - /* Disable IOV before freeing resources. This lets any VF drivers
    - * running in the host get themselves cleaned up before we yank
    - * the carpet out from underneath their feet.
    - */
    - if (!pci_vfs_assigned(pf->pdev))
    - pci_disable_sriov(pf->pdev);
    - else
    - dev_warn(&pf->pdev->dev, "VFs are assigned - not disabling SR-IOV\n");
    -
    /* free up VF resources */
    tmp = pf->num_alloc_vfs;
    pf->num_alloc_vfs = 0;
    --
    2.27.0


    \
     
     \ /
      Last update: 2020-12-01 10:40    [W:4.572 / U:0.112 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site