crypto: hisilicon - add runtime PM ops
authorWeili Qian <qianweili@huawei.com>
Fri, 13 Aug 2021 09:50:06 +0000 (17:50 +0800)
committerHerbert Xu <herbert@gondor.apana.org.au>
Sat, 21 Aug 2021 07:44:58 +0000 (15:44 +0800)
Accelerator devices support runtime PM to reduce power consumption.
This patch adds the runtime PM suspend/resume callbacks to the
accelerator devices.

Signed-off-by: Weili Qian <qianweili@huawei.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
drivers/crypto/hisilicon/qm.c
drivers/crypto/hisilicon/qm.h

index e417cd0..dbe162a 100644 (file)
@@ -5692,6 +5692,124 @@ err_pci_init:
 }
 EXPORT_SYMBOL_GPL(hisi_qm_init);
 
+
+static int qm_prepare_for_suspend(struct hisi_qm *qm)
+{
+       struct pci_dev *pdev = qm->pdev;
+       int ret;
+       u32 val;
+
+       ret = qm->ops->set_msi(qm, false);
+       if (ret) {
+               pci_err(pdev, "failed to disable MSI before suspending!\n");
+               return ret;
+       }
+
+       /* shutdown OOO register */
+       writel(ACC_MASTER_GLOBAL_CTRL_SHUTDOWN,
+              qm->io_base + ACC_MASTER_GLOBAL_CTRL);
+
+       ret = readl_relaxed_poll_timeout(qm->io_base + ACC_MASTER_TRANS_RETURN,
+                                        val,
+                                        (val == ACC_MASTER_TRANS_RETURN_RW),
+                                        POLL_PERIOD, POLL_TIMEOUT);
+       if (ret) {
+               pci_emerg(pdev, "Bus lock! Please reset system.\n");
+               return ret;
+       }
+
+       ret = qm_set_pf_mse(qm, false);
+       if (ret)
+               pci_err(pdev, "failed to disable MSE before suspending!\n");
+
+       return ret;
+}
+
+static int qm_rebuild_for_resume(struct hisi_qm *qm)
+{
+       struct pci_dev *pdev = qm->pdev;
+       int ret;
+
+       ret = qm_set_pf_mse(qm, true);
+       if (ret) {
+               pci_err(pdev, "failed to enable MSE after resuming!\n");
+               return ret;
+       }
+
+       ret = qm->ops->set_msi(qm, true);
+       if (ret) {
+               pci_err(pdev, "failed to enable MSI after resuming!\n");
+               return ret;
+       }
+
+       ret = qm_dev_hw_init(qm);
+       if (ret) {
+               pci_err(pdev, "failed to init device after resuming\n");
+               return ret;
+       }
+
+       qm_cmd_init(qm);
+       hisi_qm_dev_err_init(qm);
+
+       return 0;
+}
+
+/**
+ * hisi_qm_suspend() - Runtime suspend of given device.
+ * @dev: device to suspend.
+ *
+ * Function that suspend the device.
+ */
+int hisi_qm_suspend(struct device *dev)
+{
+       struct pci_dev *pdev = to_pci_dev(dev);
+       struct hisi_qm *qm = pci_get_drvdata(pdev);
+       int ret;
+
+       pci_info(pdev, "entering suspended state\n");
+
+       ret = hisi_qm_stop(qm, QM_NORMAL);
+       if (ret) {
+               pci_err(pdev, "failed to stop qm(%d)\n", ret);
+               return ret;
+       }
+
+       ret = qm_prepare_for_suspend(qm);
+       if (ret)
+               pci_err(pdev, "failed to prepare suspended(%d)\n", ret);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(hisi_qm_suspend);
+
+/**
+ * hisi_qm_resume() - Runtime resume of given device.
+ * @dev: device to resume.
+ *
+ * Function that resume the device.
+ */
+int hisi_qm_resume(struct device *dev)
+{
+       struct pci_dev *pdev = to_pci_dev(dev);
+       struct hisi_qm *qm = pci_get_drvdata(pdev);
+       int ret;
+
+       pci_info(pdev, "resuming from suspend state\n");
+
+       ret = qm_rebuild_for_resume(qm);
+       if (ret) {
+               pci_err(pdev, "failed to rebuild resume(%d)\n", ret);
+               return ret;
+       }
+
+       ret = hisi_qm_start(qm);
+       if (ret)
+               pci_err(pdev, "failed to start qm(%d)\n", ret);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(hisi_qm_resume);
+
 MODULE_LICENSE("GPL v2");
 MODULE_AUTHOR("Zhou Wang <wangzhou1@hisilicon.com>");
 MODULE_DESCRIPTION("HiSilicon Accelerator queue manager driver");
index 0e5df1c..59e1646 100644 (file)
@@ -431,5 +431,7 @@ void hisi_qm_dev_shutdown(struct pci_dev *pdev);
 void hisi_qm_wait_task_finish(struct hisi_qm *qm, struct hisi_qm_list *qm_list);
 int hisi_qm_alg_register(struct hisi_qm *qm, struct hisi_qm_list *qm_list);
 void hisi_qm_alg_unregister(struct hisi_qm *qm, struct hisi_qm_list *qm_list);
+int hisi_qm_resume(struct device *dev);
+int hisi_qm_suspend(struct device *dev);
 void hisi_qm_regs_dump(struct seq_file *s, struct debugfs_regset32 *regset);
 #endif