Add runtime suspend/resume for AIE4 driver.

Wake and acquire an RPM reference across amdxdna_sriov_configure() so
that SR-IOV management commands execute with the device active.

Update amdxdna_pm.c to implement amdxdna_pm_runtime_suspend() and
amdxdna_pm_runtime_resume().

Signed-off-by: David Zhang <[email protected]>
---
 drivers/accel/amdxdna/aie2_pci.c        |  2 ++
 drivers/accel/amdxdna/aie4_pci.c        | 31 ++++++++++++++++++++++
 drivers/accel/amdxdna/aie4_pci.h        |  8 ++++++
 drivers/accel/amdxdna/aie4_sriov.c      | 26 +++++++++++++++++++
 drivers/accel/amdxdna/amdxdna_pci_drv.c | 15 ++++++++---
 drivers/accel/amdxdna/amdxdna_pci_drv.h |  2 ++
 drivers/accel/amdxdna/amdxdna_pm.c      | 34 +++++++++++++++++++++++++
 drivers/accel/amdxdna/amdxdna_pm.h      |  4 ++-
 8 files changed, 118 insertions(+), 4 deletions(-)

diff --git a/drivers/accel/amdxdna/aie2_pci.c b/drivers/accel/amdxdna/aie2_pci.c
index 0d209b7b6484..f90435e1f65e 100644
--- a/drivers/accel/amdxdna/aie2_pci.c
+++ b/drivers/accel/amdxdna/aie2_pci.c
@@ -1207,6 +1207,8 @@ const struct amdxdna_dev_ops aie2_ops = {
        .fini = aie2_fini,
        .resume = aie2_hw_resume,
        .suspend = aie2_hw_suspend,
+       .runtime_resume = aie2_hw_resume,
+       .runtime_suspend = aie2_hw_suspend,
        .get_aie_info = aie2_get_info,
        .set_aie_state = aie2_set_state,
        .hwctx_init = aie2_hwctx_init,
diff --git a/drivers/accel/amdxdna/aie4_pci.c b/drivers/accel/amdxdna/aie4_pci.c
index 6a50c1499ec9..007b14be5245 100644
--- a/drivers/accel/amdxdna/aie4_pci.c
+++ b/drivers/accel/amdxdna/aie4_pci.c
@@ -1192,6 +1192,17 @@ static int aie4_pf_suspend(struct amdxdna_dev *xdna)
        return 0;
 }
 
+static int aie4_pf_runtime_suspend(struct amdxdna_dev *xdna)
+{
+       int ret;
+
+       ret = aie4_vfs_alive(xdna);
+       if (ret)
+               return ret;
+
+       return aie4_pf_suspend(xdna);
+}
+
 static int aie4_pf_resume(struct amdxdna_dev *xdna)
 {
        struct amdxdna_dev_hdl *ndev = xdna->dev_handle;
@@ -1244,6 +1255,20 @@ static int aie4_vf_suspend(struct amdxdna_dev *xdna)
        return 0;
 }
 
+static int aie4_vf_runtime_suspend(struct amdxdna_dev *xdna)
+{
+       struct amdxdna_dev_hdl *ndev = xdna->dev_handle;
+       struct pci_dev *pdev = to_pci_dev(xdna->ddev.dev);
+
+       drm_WARN_ON(&xdna->ddev, !mutex_is_locked(&xdna->dev_lock));
+       aie4_hwctx_suspend_all(ndev, false);
+       aie4_vf_hw_stop(ndev);
+       pci_disable_device(pdev);
+
+       XDNA_DBG(xdna, "vf runtime suspend done");
+       return 0;
+}
+
 static int aie4_vf_resume(struct amdxdna_dev *xdna)
 {
        struct amdxdna_dev_hdl *ndev = xdna->dev_handle;
@@ -1340,6 +1365,8 @@ const struct amdxdna_dev_ops aie4_pf_ops = {
        .sriov_configure        = aie4_sriov_configure,
        .resume                 = aie4_pf_resume,
        .suspend                = aie4_pf_suspend,
+       .runtime_resume         = aie4_pf_resume,
+       .runtime_suspend        = aie4_pf_runtime_suspend,
 };
 
 const struct amdxdna_dev_ops aie4_vf_ops = {
@@ -1354,6 +1381,8 @@ const struct amdxdna_dev_ops aie4_vf_ops = {
        .set_aie_state          = aie4_set_state,
        .resume                 = aie4_vf_resume,
        .suspend                = aie4_vf_suspend,
+       .runtime_resume         = aie4_vf_resume,
+       .runtime_suspend        = aie4_vf_runtime_suspend,
 };
 
 const struct amdxdna_dev_ops aie4_classic_ops = {
@@ -1368,4 +1397,6 @@ const struct amdxdna_dev_ops aie4_classic_ops = {
        .set_aie_state          = aie4_set_state,
        .resume                 = aie4_classic_resume,
        .suspend                = aie4_classic_suspend,
+       .runtime_resume         = aie4_classic_resume,
+       .runtime_suspend        = aie4_classic_suspend,
 };
diff --git a/drivers/accel/amdxdna/aie4_pci.h b/drivers/accel/amdxdna/aie4_pci.h
index df15c63317b1..062275be7ee7 100644
--- a/drivers/accel/amdxdna/aie4_pci.h
+++ b/drivers/accel/amdxdna/aie4_pci.h
@@ -198,16 +198,24 @@ void aie4_free_notification(struct cert_comp *comp);
 int aie4_create_vfs(struct amdxdna_dev_hdl *ndev, int num_vfs);
 int aie4_sriov_configure(struct amdxdna_dev *xdna, int num_vfs);
 int aie4_sriov_stop(struct amdxdna_dev_hdl *ndev);
+int aie4_vfs_alive(struct amdxdna_dev *xdna);
 #else
 static inline int aie4_create_vfs(struct amdxdna_dev_hdl *ndev, int num_vfs)
 {
        return 0;
 }
+
 #define aie4_sriov_configure NULL
+
 static inline int aie4_sriov_stop(struct amdxdna_dev_hdl *ndev)
 {
        return 0;
 }
+
+static inline int aie4_vfs_alive(struct amdxdna_dev *xdna)
+{
+       return 0;
+}
 #endif
 
 extern const struct amdxdna_dev_ops aie4_pf_ops;
diff --git a/drivers/accel/amdxdna/aie4_sriov.c 
b/drivers/accel/amdxdna/aie4_sriov.c
index bfea6ff00ec0..10c8a2648e23 100644
--- a/drivers/accel/amdxdna/aie4_sriov.c
+++ b/drivers/accel/amdxdna/aie4_sriov.c
@@ -6,6 +6,7 @@
 #include <drm/amdxdna_accel.h>
 #include <drm/drm_print.h>
 #include <linux/pci.h>
+#include <linux/pm_runtime.h>
 
 #include "aie.h"
 #include "aie4_msg_priv.h"
@@ -120,6 +121,31 @@ static int aie4_link_vf(struct amdxdna_dev *xdna, struct 
pci_dev *pdev_vf)
        return 0;
 }
 
+static int aie4_check_vf_alive(struct amdxdna_dev *xdna, struct pci_dev 
*pdev_vf)
+{
+       struct device_driver *drv = READ_ONCE(pdev_vf->dev.driver);
+
+       if (drv && drv->owner != THIS_MODULE) {
+               XDNA_WARN(xdna, "VF:%s is in passthrough", pci_name(pdev_vf));
+               return -EBUSY;
+       }
+
+       if (!pm_runtime_suspended(&pdev_vf->dev)) {
+               XDNA_WARN(xdna, "VF:%s is busy", pci_name(pdev_vf));
+               return -EBUSY;
+       }
+       return 0;
+}
+
+int aie4_vfs_alive(struct amdxdna_dev *xdna)
+{
+       if (pci_vfs_assigned(to_pci_dev(xdna->ddev.dev))) {
+               XDNA_WARN(xdna, "VF devices are being used in VMs, cannot 
suspend");
+               return -EBUSY;
+       }
+       return aie4_for_each_vfs(xdna, aie4_check_vf_alive);
+}
+
 static int aie4_link_vfs(struct amdxdna_dev *xdna)
 {
        return aie4_for_each_vfs(xdna, aie4_link_vf);
diff --git a/drivers/accel/amdxdna/amdxdna_pci_drv.c 
b/drivers/accel/amdxdna/amdxdna_pci_drv.c
index 1d0b91e73260..4933962844f9 100644
--- a/drivers/accel/amdxdna/amdxdna_pci_drv.c
+++ b/drivers/accel/amdxdna/amdxdna_pci_drv.c
@@ -467,18 +467,27 @@ static void amdxdna_remove(struct pci_dev *pdev)
 
 static const struct dev_pm_ops amdxdna_pm_ops = {
        SYSTEM_SLEEP_PM_OPS(amdxdna_pm_suspend, amdxdna_pm_resume)
-       RUNTIME_PM_OPS(amdxdna_pm_suspend, amdxdna_pm_resume, NULL)
+       RUNTIME_PM_OPS(amdxdna_pm_runtime_suspend, amdxdna_pm_runtime_resume, 
NULL)
 };
 
 static int amdxdna_sriov_configure(struct pci_dev *pdev, int num_vfs)
 {
        struct amdxdna_dev *xdna = pci_get_drvdata(pdev);
+       int ret;
 
        guard(mutex)(&xdna->dev_lock);
+
+       ret = amdxdna_pm_resume_get_locked(xdna);
+       if (ret)
+               return ret;
+
        if (xdna->dev_info->ops->sriov_configure)
-               return xdna->dev_info->ops->sriov_configure(xdna, num_vfs);
+               ret = xdna->dev_info->ops->sriov_configure(xdna, num_vfs);
+       else
+               ret = -EOPNOTSUPP;
 
-       return -ENOENT;
+       amdxdna_pm_suspend_put(xdna);
+       return ret;
 }
 
 static struct pci_driver amdxdna_pci_driver = {
diff --git a/drivers/accel/amdxdna/amdxdna_pci_drv.h 
b/drivers/accel/amdxdna/amdxdna_pci_drv.h
index 45170c945d71..8c735f184f00 100644
--- a/drivers/accel/amdxdna/amdxdna_pci_drv.h
+++ b/drivers/accel/amdxdna/amdxdna_pci_drv.h
@@ -57,6 +57,8 @@ struct amdxdna_dev_ops {
        void (*debugfs_init)(struct amdxdna_dev *xdna);
        int (*resume)(struct amdxdna_dev *xdna);
        int (*suspend)(struct amdxdna_dev *xdna);
+       int (*runtime_resume)(struct amdxdna_dev *xdna);
+       int (*runtime_suspend)(struct amdxdna_dev *xdna);
        int (*sriov_configure)(struct amdxdna_dev *xdna, int num_vfs);
        int (*hwctx_init)(struct amdxdna_hwctx *hwctx);
        void (*hwctx_fini)(struct amdxdna_hwctx *hwctx);
diff --git a/drivers/accel/amdxdna/amdxdna_pm.c 
b/drivers/accel/amdxdna/amdxdna_pm.c
index 9c030b7836fb..2b4ce301bb96 100644
--- a/drivers/accel/amdxdna/amdxdna_pm.c
+++ b/drivers/accel/amdxdna/amdxdna_pm.c
@@ -37,11 +37,40 @@ int amdxdna_pm_resume(struct device *dev)
        return ret;
 }
 
+int amdxdna_pm_runtime_suspend(struct device *dev)
+{
+       struct amdxdna_dev *xdna = to_xdna_dev(dev_get_drvdata(dev));
+       int ret = -EOPNOTSUPP;
+
+       guard(mutex)(&xdna->dev_lock);
+       if (xdna->dev_info->ops->runtime_suspend)
+               ret = xdna->dev_info->ops->runtime_suspend(xdna);
+
+       XDNA_DBG(xdna, "Runtime suspend done ret %d", ret);
+       return ret;
+}
+
+int amdxdna_pm_runtime_resume(struct device *dev)
+{
+       struct amdxdna_dev *xdna = to_xdna_dev(dev_get_drvdata(dev));
+       int ret = -EOPNOTSUPP;
+
+       guard(mutex)(&xdna->dev_lock);
+       if (xdna->dev_info->ops->runtime_resume)
+               ret = xdna->dev_info->ops->runtime_resume(xdna);
+
+       XDNA_DBG(xdna, "Runtime resume done ret %d", ret);
+       return ret;
+}
+
 int amdxdna_pm_resume_get(struct amdxdna_dev *xdna)
 {
        struct device *dev = xdna->ddev.dev;
        int ret;
 
+       if (!pm_runtime_enabled(dev))
+               return 0;
+
        ret = pm_runtime_resume_and_get(dev);
        if (ret) {
                XDNA_ERR(xdna, "Resume failed: %d", ret);
@@ -55,6 +84,10 @@ void amdxdna_pm_suspend_put(struct amdxdna_dev *xdna)
 {
        struct device *dev = xdna->ddev.dev;
 
+       if (!pm_runtime_enabled(dev))
+               return;
+
+       pm_runtime_mark_last_busy(dev);
        pm_runtime_put_autosuspend(dev);
 }
 
@@ -66,6 +99,7 @@ void amdxdna_pm_init(struct amdxdna_dev *xdna)
        pm_runtime_set_autosuspend_delay(dev, AMDXDNA_AUTOSUSPEND_DELAY);
        pm_runtime_use_autosuspend(dev);
        pm_runtime_allow(dev);
+       pm_runtime_mark_last_busy(dev);
        pm_runtime_put_autosuspend(dev);
 }
 
diff --git a/drivers/accel/amdxdna/amdxdna_pm.h 
b/drivers/accel/amdxdna/amdxdna_pm.h
index 3d26b973e0e3..26df3d50d8ea 100644
--- a/drivers/accel/amdxdna/amdxdna_pm.h
+++ b/drivers/accel/amdxdna/amdxdna_pm.h
@@ -9,7 +9,9 @@
 #include "amdxdna_pci_drv.h"
 
 int amdxdna_pm_suspend(struct device *dev);
-int amdxdna_pm_resume(struct device  *dev);
+int amdxdna_pm_resume(struct device *dev);
+int amdxdna_pm_runtime_suspend(struct device *dev);
+int amdxdna_pm_runtime_resume(struct device *dev);
 int amdxdna_pm_resume_get(struct amdxdna_dev *xdna);
 void amdxdna_pm_suspend_put(struct amdxdna_dev *xdna);
 void amdxdna_pm_init(struct amdxdna_dev *xdna);
-- 
2.34.1

Reply via email to