net: aquantia: Implement pci shutdown callback

We should close link and all NIC operations during shutdown.
On some systems graceful reboot never closes NIC interface on its own,
but only indicates pci device shutdown. Without explicit handler, NIC
rx rings continued to transfer DMA data into prepared buffers while CPU
rebooted already. That caused memory corruptions on soft reboot.

Signed-off-by: Igor Russkikh <igor.russkikh@aquantia.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Igor Russkikh 2018-03-20 14:40:36 +03:00 committed by David S. Miller
parent 3e9a545131
commit 90869ddfef
3 changed files with 36 additions and 0 deletions

View File

@ -939,3 +939,23 @@ int aq_nic_change_pm_state(struct aq_nic_s *self, pm_message_t *pm_msg)
out:
return err;
}
void aq_nic_shutdown(struct aq_nic_s *self)
{
int err = 0;
if (!self->ndev)
return;
rtnl_lock();
netif_device_detach(self->ndev);
err = aq_nic_stop(self);
if (err < 0)
goto err_exit;
aq_nic_deinit(self);
err_exit:
rtnl_unlock();
}

View File

@ -118,5 +118,6 @@ 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);
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);
void aq_nic_shutdown(struct aq_nic_s *self);
#endif /* AQ_NIC_H */

View File

@ -323,6 +323,20 @@ static void aq_pci_remove(struct pci_dev *pdev)
pci_disable_device(pdev);
}
static void aq_pci_shutdown(struct pci_dev *pdev)
{
struct aq_nic_s *self = pci_get_drvdata(pdev);
aq_nic_shutdown(self);
pci_disable_device(pdev);
if (system_state == SYSTEM_POWER_OFF) {
pci_wake_from_d3(pdev, false);
pci_set_power_state(pdev, PCI_D3hot);
}
}
static int aq_pci_suspend(struct pci_dev *pdev, pm_message_t pm_msg)
{
struct aq_nic_s *self = pci_get_drvdata(pdev);
@ -345,6 +359,7 @@ static struct pci_driver aq_pci_ops = {
.remove = aq_pci_remove,
.suspend = aq_pci_suspend,
.resume = aq_pci_resume,
.shutdown = aq_pci_shutdown,
};
module_pci_driver(aq_pci_ops);