Commit 218ed820 authored by Thinh Tran's avatar Thinh Tran Committed by Jakub Kicinski

i40e: factoring out i40e_suspend/i40e_resume

Two new functions, i40e_io_suspend() and i40e_io_resume(), have been
introduced.  These functions were factored out from the existing
i40e_suspend() and i40e_resume() respectively.  This factoring was
done due to concerns about the logic of the I40E_SUSPENSED state, which
caused the device to be unable to recover.  The functions are now used
in the EEH handling for device suspend/resume callbacks.

The function i40e_enable_mc_magic_wake() has been moved ahead of
i40e_io_suspend() to ensure it is declared before being used.
Tested-by: default avatarRobert Thomas <rob.thomas@ibm.com>
Signed-off-by: default avatarThinh Tran <thinhtr@linux.ibm.com>
Reviewed-by: default avatarSimon Horman <horms@kernel.org>
Tested-by: default avatarPucha Himasekhar Reddy <himasekharx.reddy.pucha@intel.com>
Reviewed-by: default avatarJacob Keller <jacob.e.keller@intel.com>
Signed-off-by: default avatarJacob Keller <jacob.e.keller@intel.com>
Link: https://lore.kernel.org/r/20240528-net-2024-05-28-intel-net-fixes-v1-2-dc8593d2bbc6@intel.comSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent bfd546a5
...@@ -16334,6 +16334,139 @@ static void i40e_remove(struct pci_dev *pdev) ...@@ -16334,6 +16334,139 @@ static void i40e_remove(struct pci_dev *pdev)
pci_disable_device(pdev); pci_disable_device(pdev);
} }
/**
* i40e_enable_mc_magic_wake - enable multicast magic packet wake up
* using the mac_address_write admin q function
* @pf: pointer to i40e_pf struct
**/
static void i40e_enable_mc_magic_wake(struct i40e_pf *pf)
{
struct i40e_vsi *main_vsi = i40e_pf_get_main_vsi(pf);
struct i40e_hw *hw = &pf->hw;
u8 mac_addr[6];
u16 flags = 0;
int ret;
/* Get current MAC address in case it's an LAA */
if (main_vsi && main_vsi->netdev) {
ether_addr_copy(mac_addr, main_vsi->netdev->dev_addr);
} else {
dev_err(&pf->pdev->dev,
"Failed to retrieve MAC address; using default\n");
ether_addr_copy(mac_addr, hw->mac.addr);
}
/* The FW expects the mac address write cmd to first be called with
* one of these flags before calling it again with the multicast
* enable flags.
*/
flags = I40E_AQC_WRITE_TYPE_LAA_WOL;
if (hw->func_caps.flex10_enable && hw->partition_id != 1)
flags = I40E_AQC_WRITE_TYPE_LAA_ONLY;
ret = i40e_aq_mac_address_write(hw, flags, mac_addr, NULL);
if (ret) {
dev_err(&pf->pdev->dev,
"Failed to update MAC address registers; cannot enable Multicast Magic packet wake up");
return;
}
flags = I40E_AQC_MC_MAG_EN
| I40E_AQC_WOL_PRESERVE_ON_PFR
| I40E_AQC_WRITE_TYPE_UPDATE_MC_MAG;
ret = i40e_aq_mac_address_write(hw, flags, mac_addr, NULL);
if (ret)
dev_err(&pf->pdev->dev,
"Failed to enable Multicast Magic Packet wake up\n");
}
/**
* i40e_io_suspend - suspend all IO operations
* @pf: pointer to i40e_pf struct
*
**/
static int i40e_io_suspend(struct i40e_pf *pf)
{
struct i40e_hw *hw = &pf->hw;
set_bit(__I40E_DOWN, pf->state);
/* Ensure service task will not be running */
del_timer_sync(&pf->service_timer);
cancel_work_sync(&pf->service_task);
/* Client close must be called explicitly here because the timer
* has been stopped.
*/
i40e_notify_client_of_netdev_close(pf, false);
if (test_bit(I40E_HW_CAP_WOL_MC_MAGIC_PKT_WAKE, pf->hw.caps) &&
pf->wol_en)
i40e_enable_mc_magic_wake(pf);
/* Since we're going to destroy queues during the
* i40e_clear_interrupt_scheme() we should hold the RTNL lock for this
* whole section
*/
rtnl_lock();
i40e_prep_for_reset(pf);
wr32(hw, I40E_PFPM_APM, (pf->wol_en ? I40E_PFPM_APM_APME_MASK : 0));
wr32(hw, I40E_PFPM_WUFC, (pf->wol_en ? I40E_PFPM_WUFC_MAG_MASK : 0));
/* Clear the interrupt scheme and release our IRQs so that the system
* can safely hibernate even when there are a large number of CPUs.
* Otherwise hibernation might fail when mapping all the vectors back
* to CPU0.
*/
i40e_clear_interrupt_scheme(pf);
rtnl_unlock();
return 0;
}
/**
* i40e_io_resume - resume IO operations
* @pf: pointer to i40e_pf struct
*
**/
static int i40e_io_resume(struct i40e_pf *pf)
{
struct device *dev = &pf->pdev->dev;
int err;
/* We need to hold the RTNL lock prior to restoring interrupt schemes,
* since we're going to be restoring queues
*/
rtnl_lock();
/* We cleared the interrupt scheme when we suspended, so we need to
* restore it now to resume device functionality.
*/
err = i40e_restore_interrupt_scheme(pf);
if (err) {
dev_err(dev, "Cannot restore interrupt scheme: %d\n",
err);
}
clear_bit(__I40E_DOWN, pf->state);
i40e_reset_and_rebuild(pf, false, true);
rtnl_unlock();
/* Clear suspended state last after everything is recovered */
clear_bit(__I40E_SUSPENDED, pf->state);
/* Restart the service task */
mod_timer(&pf->service_timer,
round_jiffies(jiffies + pf->service_timer_period));
return 0;
}
/** /**
* i40e_pci_error_detected - warning that something funky happened in PCI land * i40e_pci_error_detected - warning that something funky happened in PCI land
* @pdev: PCI device information struct * @pdev: PCI device information struct
...@@ -16446,53 +16579,6 @@ static void i40e_pci_error_resume(struct pci_dev *pdev) ...@@ -16446,53 +16579,6 @@ static void i40e_pci_error_resume(struct pci_dev *pdev)
i40e_handle_reset_warning(pf, false); i40e_handle_reset_warning(pf, false);
} }
/**
* i40e_enable_mc_magic_wake - enable multicast magic packet wake up
* using the mac_address_write admin q function
* @pf: pointer to i40e_pf struct
**/
static void i40e_enable_mc_magic_wake(struct i40e_pf *pf)
{
struct i40e_vsi *main_vsi = i40e_pf_get_main_vsi(pf);
struct i40e_hw *hw = &pf->hw;
u8 mac_addr[6];
u16 flags = 0;
int ret;
/* Get current MAC address in case it's an LAA */
if (main_vsi && main_vsi->netdev) {
ether_addr_copy(mac_addr, main_vsi->netdev->dev_addr);
} else {
dev_err(&pf->pdev->dev,
"Failed to retrieve MAC address; using default\n");
ether_addr_copy(mac_addr, hw->mac.addr);
}
/* The FW expects the mac address write cmd to first be called with
* one of these flags before calling it again with the multicast
* enable flags.
*/
flags = I40E_AQC_WRITE_TYPE_LAA_WOL;
if (hw->func_caps.flex10_enable && hw->partition_id != 1)
flags = I40E_AQC_WRITE_TYPE_LAA_ONLY;
ret = i40e_aq_mac_address_write(hw, flags, mac_addr, NULL);
if (ret) {
dev_err(&pf->pdev->dev,
"Failed to update MAC address registers; cannot enable Multicast Magic packet wake up");
return;
}
flags = I40E_AQC_MC_MAG_EN
| I40E_AQC_WOL_PRESERVE_ON_PFR
| I40E_AQC_WRITE_TYPE_UPDATE_MC_MAG;
ret = i40e_aq_mac_address_write(hw, flags, mac_addr, NULL);
if (ret)
dev_err(&pf->pdev->dev,
"Failed to enable Multicast Magic Packet wake up\n");
}
/** /**
* i40e_shutdown - PCI callback for shutting down * i40e_shutdown - PCI callback for shutting down
* @pdev: PCI device information struct * @pdev: PCI device information struct
...@@ -16552,48 +16638,11 @@ static void i40e_shutdown(struct pci_dev *pdev) ...@@ -16552,48 +16638,11 @@ static void i40e_shutdown(struct pci_dev *pdev)
static int i40e_suspend(struct device *dev) static int i40e_suspend(struct device *dev)
{ {
struct i40e_pf *pf = dev_get_drvdata(dev); struct i40e_pf *pf = dev_get_drvdata(dev);
struct i40e_hw *hw = &pf->hw;
/* If we're already suspended, then there is nothing to do */ /* If we're already suspended, then there is nothing to do */
if (test_and_set_bit(__I40E_SUSPENDED, pf->state)) if (test_and_set_bit(__I40E_SUSPENDED, pf->state))
return 0; return 0;
return i40e_io_suspend(pf);
set_bit(__I40E_DOWN, pf->state);
/* Ensure service task will not be running */
del_timer_sync(&pf->service_timer);
cancel_work_sync(&pf->service_task);
/* Client close must be called explicitly here because the timer
* has been stopped.
*/
i40e_notify_client_of_netdev_close(pf, false);
if (test_bit(I40E_HW_CAP_WOL_MC_MAGIC_PKT_WAKE, pf->hw.caps) &&
pf->wol_en)
i40e_enable_mc_magic_wake(pf);
/* Since we're going to destroy queues during the
* i40e_clear_interrupt_scheme() we should hold the RTNL lock for this
* whole section
*/
rtnl_lock();
i40e_prep_for_reset(pf);
wr32(hw, I40E_PFPM_APM, (pf->wol_en ? I40E_PFPM_APM_APME_MASK : 0));
wr32(hw, I40E_PFPM_WUFC, (pf->wol_en ? I40E_PFPM_WUFC_MAG_MASK : 0));
/* Clear the interrupt scheme and release our IRQs so that the system
* can safely hibernate even when there are a large number of CPUs.
* Otherwise hibernation might fail when mapping all the vectors back
* to CPU0.
*/
i40e_clear_interrupt_scheme(pf);
rtnl_unlock();
return 0;
} }
/** /**
...@@ -16603,39 +16652,11 @@ static int i40e_suspend(struct device *dev) ...@@ -16603,39 +16652,11 @@ static int i40e_suspend(struct device *dev)
static int i40e_resume(struct device *dev) static int i40e_resume(struct device *dev)
{ {
struct i40e_pf *pf = dev_get_drvdata(dev); struct i40e_pf *pf = dev_get_drvdata(dev);
int err;
/* If we're not suspended, then there is nothing to do */ /* If we're not suspended, then there is nothing to do */
if (!test_bit(__I40E_SUSPENDED, pf->state)) if (!test_bit(__I40E_SUSPENDED, pf->state))
return 0; return 0;
return i40e_io_resume(pf);
/* We need to hold the RTNL lock prior to restoring interrupt schemes,
* since we're going to be restoring queues
*/
rtnl_lock();
/* We cleared the interrupt scheme when we suspended, so we need to
* restore it now to resume device functionality.
*/
err = i40e_restore_interrupt_scheme(pf);
if (err) {
dev_err(dev, "Cannot restore interrupt scheme: %d\n",
err);
}
clear_bit(__I40E_DOWN, pf->state);
i40e_reset_and_rebuild(pf, false, true);
rtnl_unlock();
/* Clear suspended state last after everything is recovered */
clear_bit(__I40E_SUSPENDED, pf->state);
/* Restart the service task */
mod_timer(&pf->service_timer,
round_jiffies(jiffies + pf->service_timer_period));
return 0;
} }
static const struct pci_error_handlers i40e_err_handler = { static const struct pci_error_handlers i40e_err_handler = {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment