net: atlantic: refactoring pm logic

We now implement .driver.pm callbacks, these
allows driver to work correctly in hibernate
usecases, especially when used in conjunction with
WOL feature.

Before that driver only reacted to legacy .suspend/.resume
callbacks, that was a limitation in some cases.

Signed-off-by: Nikita Danilov <ndanilov@marvell.com>
Signed-off-by: Igor Russkikh <irusskikh@marvell.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Nikita Danilov 2019-11-07 22:41:52 +00:00 committed by David S. Miller
parent 837c637869
commit 8aaa112a57
3 changed files with 78 additions and 48 deletions

View File

@ -1057,44 +1057,6 @@ void aq_nic_free_vectors(struct aq_nic_s *self)
err_exit:; err_exit:;
} }
int aq_nic_change_pm_state(struct aq_nic_s *self, pm_message_t *pm_msg)
{
int err = 0;
if (!netif_running(self->ndev)) {
err = 0;
goto out;
}
rtnl_lock();
if (pm_msg->event & PM_EVENT_SLEEP || pm_msg->event & PM_EVENT_FREEZE) {
self->power_state = AQ_HW_POWER_STATE_D3;
netif_device_detach(self->ndev);
netif_tx_stop_all_queues(self->ndev);
err = aq_nic_stop(self);
if (err < 0)
goto err_exit;
aq_nic_deinit(self, !self->aq_hw->aq_nic_cfg->wol);
} else {
err = aq_nic_init(self);
if (err < 0)
goto err_exit;
err = aq_nic_start(self);
if (err < 0)
goto err_exit;
netif_device_attach(self->ndev);
netif_tx_start_all_queues(self->ndev);
}
err_exit:
rtnl_unlock();
out:
return err;
}
void aq_nic_shutdown(struct aq_nic_s *self) void aq_nic_shutdown(struct aq_nic_s *self)
{ {
int err = 0; int err = 0;

View File

@ -157,7 +157,6 @@ int aq_nic_set_link_ksettings(struct aq_nic_s *self,
const struct ethtool_link_ksettings *cmd); const struct ethtool_link_ksettings *cmd);
struct aq_nic_cfg_s *aq_nic_get_cfg(struct aq_nic_s *self); struct aq_nic_cfg_s *aq_nic_get_cfg(struct aq_nic_s *self);
u32 aq_nic_get_fw_version(struct aq_nic_s *self); u32 aq_nic_get_fw_version(struct aq_nic_s *self);
int aq_nic_change_pm_state(struct aq_nic_s *self, pm_message_t *pm_msg);
int aq_nic_update_interrupt_moderation_settings(struct aq_nic_s *self); int aq_nic_update_interrupt_moderation_settings(struct aq_nic_s *self);
void aq_nic_shutdown(struct aq_nic_s *self); void aq_nic_shutdown(struct aq_nic_s *self);
u8 aq_nic_reserve_filter(struct aq_nic_s *self, enum aq_rx_filter_type type); u8 aq_nic_reserve_filter(struct aq_nic_s *self, enum aq_rx_filter_type type);

View File

@ -347,29 +347,98 @@ static void aq_pci_shutdown(struct pci_dev *pdev)
} }
} }
static int aq_pci_suspend(struct pci_dev *pdev, pm_message_t pm_msg) static int aq_suspend_common(struct device *dev, bool deep)
{ {
struct aq_nic_s *self = pci_get_drvdata(pdev); struct aq_nic_s *nic = pci_get_drvdata(to_pci_dev(dev));
return aq_nic_change_pm_state(self, &pm_msg); rtnl_lock();
nic->power_state = AQ_HW_POWER_STATE_D3;
netif_device_detach(nic->ndev);
netif_tx_stop_all_queues(nic->ndev);
aq_nic_stop(nic);
if (deep) {
aq_nic_deinit(nic, !nic->aq_hw->aq_nic_cfg->wol);
aq_nic_set_power(nic);
} }
static int aq_pci_resume(struct pci_dev *pdev) rtnl_unlock();
{
struct aq_nic_s *self = pci_get_drvdata(pdev);
pm_message_t pm_msg = PMSG_RESTORE;
return aq_nic_change_pm_state(self, &pm_msg); return 0;
} }
static int atl_resume_common(struct device *dev, bool deep)
{
struct pci_dev *pdev = to_pci_dev(dev);
struct aq_nic_s *nic;
int ret;
nic = pci_get_drvdata(pdev);
rtnl_lock();
pci_set_power_state(pdev, PCI_D0);
pci_restore_state(pdev);
if (deep) {
ret = aq_nic_init(nic);
if (ret)
goto err_exit;
}
ret = aq_nic_start(nic);
if (ret)
goto err_exit;
netif_device_attach(nic->ndev);
netif_tx_start_all_queues(nic->ndev);
err_exit:
rtnl_unlock();
return ret;
}
static int aq_pm_freeze(struct device *dev)
{
return aq_suspend_common(dev, false);
}
static int aq_pm_suspend_poweroff(struct device *dev)
{
return aq_suspend_common(dev, true);
}
static int aq_pm_thaw(struct device *dev)
{
return atl_resume_common(dev, false);
}
static int aq_pm_resume_restore(struct device *dev)
{
return atl_resume_common(dev, true);
}
const struct dev_pm_ops aq_pm_ops = {
.suspend = aq_pm_suspend_poweroff,
.poweroff = aq_pm_suspend_poweroff,
.freeze = aq_pm_freeze,
.resume = aq_pm_resume_restore,
.restore = aq_pm_resume_restore,
.thaw = aq_pm_thaw,
};
static struct pci_driver aq_pci_ops = { static struct pci_driver aq_pci_ops = {
.name = AQ_CFG_DRV_NAME, .name = AQ_CFG_DRV_NAME,
.id_table = aq_pci_tbl, .id_table = aq_pci_tbl,
.probe = aq_pci_probe, .probe = aq_pci_probe,
.remove = aq_pci_remove, .remove = aq_pci_remove,
.suspend = aq_pci_suspend,
.resume = aq_pci_resume,
.shutdown = aq_pci_shutdown, .shutdown = aq_pci_shutdown,
#ifdef CONFIG_PM
.driver.pm = &aq_pm_ops,
#endif
}; };
int aq_pci_func_register_driver(void) int aq_pci_func_register_driver(void)