[PATCH v5 09/10] gna: add power management
Maciej Kwapulinski
maciej.kwapulinski at linux.intel.com
Thu Oct 20 17:53:33 UTC 2022
Implement power management in GNA driver
Signed-off-by: Maciej Kwapulinski <maciej.kwapulinski at linux.intel.com>
Tested-by: Mikolaj Grzybowski <mikolajx.grzybowski at intel.com>
Co-developed-by: Tomasz Jankowski <tomasz1.jankowski at intel.com>
Signed-off-by: Tomasz Jankowski <tomasz1.jankowski at intel.com>
Co-developed-by: Jianxun Zhang <jianxun.zhang at linux.intel.com>
Signed-off-by: Jianxun Zhang <jianxun.zhang at linux.intel.com>
---
drivers/gpu/drm/gna/gna_device.c | 47 +++++++++++++++++++++++++++++++
drivers/gpu/drm/gna/gna_device.h | 3 ++
drivers/gpu/drm/gna/gna_pci.c | 3 ++
drivers/gpu/drm/gna/gna_request.c | 15 ++++++++++
4 files changed, 68 insertions(+)
diff --git a/drivers/gpu/drm/gna/gna_device.c b/drivers/gpu/drm/gna/gna_device.c
index 2ef5be16dc9a..aee409e3b4ea 100644
--- a/drivers/gpu/drm/gna/gna_device.c
+++ b/drivers/gpu/drm/gna/gna_device.c
@@ -32,6 +32,32 @@ static const struct drm_ioctl_desc gna_drm_ioctls[] = {
DRM_IOCTL_DEF_DRV(GNA_WAIT, gna_wait_ioctl, DRM_RENDER_ALLOW),
};
+static int __maybe_unused gna_runtime_suspend(struct device *dev)
+{
+ struct drm_device *drm_dev = dev_get_drvdata(dev);
+ struct gna_device *gna_priv = to_gna_device(drm_dev);
+ u32 val = gna_reg_read(gna_priv, GNA_MMIO_D0I3C);
+
+ dev_dbg(dev, "%s D0I3, reg %.8x\n", __func__, val);
+
+ return 0;
+}
+
+static int __maybe_unused gna_runtime_resume(struct device *dev)
+{
+ struct drm_device *drm_dev = dev_get_drvdata(dev);
+ struct gna_device *gna_priv = to_gna_device(drm_dev);
+ u32 val = gna_reg_read(gna_priv, GNA_MMIO_D0I3C);
+
+ dev_dbg(dev, "%s D0I3, reg %.8x\n", __func__, val);
+
+ return 0;
+}
+
+const struct dev_pm_ops __maybe_unused gna_pm = {
+ SET_RUNTIME_PM_OPS(gna_runtime_suspend, gna_runtime_resume, NULL)
+};
+
static void gna_drm_dev_fini(struct drm_device *dev, void *ptr)
{
@@ -49,6 +75,22 @@ static int gna_drm_dev_init(struct drm_device *dev)
return drmm_add_action_or_reset(dev, gna_drm_dev_fini, NULL);
}
+static void gna_pm_init(struct device *dev)
+{
+ pm_runtime_set_autosuspend_delay(dev, 2000);
+ pm_runtime_use_autosuspend(dev);
+ pm_runtime_mark_last_busy(dev);
+ pm_runtime_allow(dev);
+ pm_runtime_put_noidle(dev);
+}
+
+static void gna_pm_fini(struct drm_device *drm, void *data)
+{
+ struct device *dev = data;
+
+ pm_runtime_get_noresume(dev);
+}
+
static irqreturn_t gna_interrupt(int irq, void *priv)
{
struct gna_device *gna_priv;
@@ -170,6 +212,11 @@ int gna_probe(struct device *parent, struct gna_dev_info *dev_info, void __iomem
if (err)
return err;
+ gna_pm_init(parent);
+ err = drmm_add_action(drm_dev, gna_pm_fini, parent);
+ if (err)
+ return err;
+
return 0;
}
diff --git a/drivers/gpu/drm/gna/gna_device.h b/drivers/gpu/drm/gna/gna_device.h
index ffdc3d1d1f87..6eae0f2f44df 100644
--- a/drivers/gpu/drm/gna/gna_device.h
+++ b/drivers/gpu/drm/gna/gna_device.h
@@ -11,6 +11,7 @@
#include <linux/io.h>
#include <linux/list.h>
#include <linux/mutex.h>
+#include <linux/pm_runtime.h>
#include <linux/types.h>
#include "gna_gem.h"
@@ -78,6 +79,8 @@ int gna_score_ioctl(struct drm_device *dev, void *data,
int gna_wait_ioctl(struct drm_device *dev, void *data,
struct drm_file *file);
+extern const struct dev_pm_ops __maybe_unused gna_pm;
+
static inline u32 gna_reg_read(struct gna_device *gna_priv, u32 reg)
{
return readl(gna_priv->iobase + reg);
diff --git a/drivers/gpu/drm/gna/gna_pci.c b/drivers/gpu/drm/gna/gna_pci.c
index 034554b417a8..eaae42142bfb 100644
--- a/drivers/gpu/drm/gna/gna_pci.c
+++ b/drivers/gpu/drm/gna/gna_pci.c
@@ -138,6 +138,9 @@ static struct pci_driver gna_pci_driver = {
.name = DRIVER_NAME,
.id_table = gna_pci_ids,
.probe = gna_pci_probe,
+ .driver = {
+ .pm = &gna_pm,
+ },
};
module_pci_driver(gna_pci_driver);
diff --git a/drivers/gpu/drm/gna/gna_request.c b/drivers/gpu/drm/gna/gna_request.c
index 9efaea61ac68..1d9572bedcc2 100644
--- a/drivers/gpu/drm/gna/gna_request.c
+++ b/drivers/gpu/drm/gna/gna_request.c
@@ -11,6 +11,7 @@
#include <linux/list.h>
#include <linux/math.h>
#include <linux/mutex.h>
+#include <linux/pm_runtime.h>
#include <linux/slab.h>
#include <linux/timekeeping.h>
#include <linux/uaccess.h>
@@ -110,6 +111,14 @@ static void gna_request_process(struct work_struct *work)
score_request->drv_perf.pre_processing = ktime_get_ns();
+ ret = pm_runtime_get_sync(gna_dev(gna_priv));
+ if (ret < 0 && ret != -EACCES) {
+ dev_warn(gna_dev(gna_priv), "pm_runtime_get_sync() failed: %d\n", ret);
+ score_request->status = -ENODEV;
+ pm_runtime_put_noidle(gna_dev(gna_priv));
+ goto tail;
+ }
+
/* Set busy flag before kicking off HW. The isr will clear it and wake up us. There is
* no difference if isr is missed in a timeout situation of the last request. We just
* always set it busy and let the wait_event_timeout check the reset.
@@ -120,6 +129,8 @@ static void gna_request_process(struct work_struct *work)
ret = gna_score(score_request);
if (ret) {
+ if (pm_runtime_put(gna_dev(gna_priv)) < 0)
+ dev_warn(gna_dev(gna_priv), "pm_runtime_put() failed: %d\n", ret);
score_request->status = ret;
goto tail;
}
@@ -142,6 +153,10 @@ static void gna_request_process(struct work_struct *work)
if (ret < 0 && score_request->status == 0)
score_request->status = ret; // -ETIMEDOUT
+ ret = pm_runtime_put(gna_dev(gna_priv));
+ if (ret < 0)
+ dev_warn(gna_dev(gna_priv), "pm_runtime_put() failed: %d\n", ret);
+
gna_mmu_clear(gna_priv);
for (i = 0, buffer = score_request->buffer_list; i < score_request->buffer_count; i++, buffer++)
--
2.25.1
More information about the dri-devel
mailing list