From: Hao Shen shenhao21@huawei.com
The suspend and resume feature is useful when you want to save the current state of your machine, and continue work later from the same state. This patch makes the hns3 net device work form the same state after s3 and s4.
Signed-off-by: Weiwei Deng dengweiwei@huawei.com Signed-off-by: Hao Shen shenhao21@huawei.com Signed-off-by: Jian Shen shenjian15@huawei.com --- drivers/net/ethernet/hisilicon/hns3/hnae3.h | 2 + drivers/net/ethernet/hisilicon/hns3/hns3_enet.c | 32 ++++++++++ .../ethernet/hisilicon/hns3/hns3pf/hclge_main.c | 70 ++++++++++++++++++++++ 3 files changed, 104 insertions(+)
diff --git a/drivers/net/ethernet/hisilicon/hns3/hnae3.h b/drivers/net/ethernet/hisilicon/hns3/hnae3.h index bb29b46..8b1e690 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hnae3.h +++ b/drivers/net/ethernet/hisilicon/hns3/hnae3.h @@ -561,6 +561,8 @@ struct hnae3_ae_ops { int (*set_vf_mac)(struct hnae3_handle *handle, int vf, u8 *p); int (*get_module_eeprom)(struct hnae3_handle *handle, u32 offset, u32 len, u8 *data); + int (*suspend)(struct hnae3_ae_dev *ae_dev); + int (*resume)(struct hnae3_ae_dev *ae_dev); };
struct hnae3_dcb_ops { diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c index 4eca8cf..de3d37c3 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -2226,6 +2226,34 @@ static void hns3_shutdown(struct pci_dev *pdev) pci_set_power_state(pdev, PCI_D3hot); }
+#ifdef CONFIG_PM +static int hns3_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct hnae3_ae_dev *ae_dev = pci_get_drvdata(pdev); + + if (ae_dev->ops->suspend) + ae_dev->ops->suspend(ae_dev); + + pci_save_state(pdev); + pci_set_power_state(pdev, PCI_D3hot); + + return 0; +} + +static int hns3_resume(struct pci_dev *pdev) +{ + struct hnae3_ae_dev *ae_dev = pci_get_drvdata(pdev); + + pci_set_power_state(pdev, PCI_D0); + pci_restore_state(pdev); + + if (ae_dev->ops->resume) + return ae_dev->ops->resume(ae_dev); + + return 0; +} +#endif + static pci_ers_result_t hns3_error_detected(struct pci_dev *pdev, pci_channel_state_t state) { @@ -2310,6 +2338,10 @@ struct pci_driver hns3_driver = { .probe = hns3_probe, .remove = hns3_remove, .shutdown = hns3_shutdown, +#ifdef CONFIG_PM + .suspend = hns3_suspend, + .resume = hns3_resume, +#endif .sriov_configure = hns3_pci_sriov_configure, .err_handler = &hns3_err_handler, }; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index c2ae05f..478a3b5 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -3820,6 +3820,72 @@ static void hclge_reset(struct hclge_dev *hdev) hclge_reset_task_schedule(hdev); }
+#ifdef CONFIG_PM +static int hclge_suspend(struct hnae3_ae_dev *ae_dev) +{ + struct hclge_dev *hdev = ae_dev->priv; + int ret; + + ret = hclge_notify_roce_client(hdev, HNAE3_DOWN_CLIENT); + if (ret) + return ret; + + rtnl_lock(); + + ret = hclge_notify_client(hdev, HNAE3_DOWN_CLIENT); + if (ret) + goto err_reset_lock; + + ret = hclge_notify_client(hdev, HNAE3_UNINIT_CLIENT); + if (ret) + goto err_reset_lock; + + rtnl_unlock(); + + return hclge_notify_roce_client(hdev, HNAE3_UNINIT_CLIENT); + +err_reset_lock: + rtnl_unlock(); + return ret; +} + +static int hclge_resume(struct hnae3_ae_dev *ae_dev) +{ + struct hclge_dev *hdev = ae_dev->priv; + int ret; + + rtnl_lock(); + + ret = hclge_reset_ae_dev(hdev->ae_dev); + if (ret) + goto err_reset_lock; + + ret = hclge_notify_client(hdev, HNAE3_INIT_CLIENT); + if (ret) + goto err_reset_lock; + + rtnl_unlock(); + + ret = hclge_notify_roce_client(hdev, HNAE3_INIT_CLIENT); + if (ret) + goto err_reset_lock; + + rtnl_lock(); + + ret = hclge_notify_client(hdev, HNAE3_UP_CLIENT); + if (ret) + goto err_reset_lock; + + rtnl_unlock(); + + return hclge_notify_roce_client(hdev, HNAE3_UP_CLIENT); + +err_reset_lock: + rtnl_unlock(); + return ret; +} +#endif + static void hclge_reset_event(struct pci_dev *pdev, struct hnae3_handle *handle) { struct hnae3_ae_dev *ae_dev = pci_get_drvdata(pdev); @@ -11525,6 +11591,10 @@ struct hnae3_ae_ops hclge_ops = { .set_vf_rate = hclge_set_vf_rate, .set_vf_mac = hclge_set_vf_mac, .get_module_eeprom = hclge_get_module_eeprom, +#ifdef CONFIG_PM + .suspend = hclge_suspend, + .resume = hclge_resume, +#endif };
static struct hnae3_ae_algo ae_algo = {