summaryrefslogtreecommitdiff
path: root/drivers/accel/ivpu/ivpu_pm.c
diff options
context:
space:
mode:
authorJacek Lawrynowicz <jacek.lawrynowicz@linux.intel.com>2024-06-11 14:04:23 +0200
committerJacek Lawrynowicz <jacek.lawrynowicz@linux.intel.com>2024-06-14 09:13:32 +0200
commita19bffb10c46744760e3c91cf6b5b58a998a4ba9 (patch)
treeebfcdc0f54fa0366fc0d045a938a7cb9b56446ff /drivers/accel/ivpu/ivpu_pm.c
parentab4484cd863b3637ec8e03318532785476d12dfc (diff)
downloadlinux-a19bffb10c46744760e3c91cf6b5b58a998a4ba9.tar.gz
linux-a19bffb10c46744760e3c91cf6b5b58a998a4ba9.tar.bz2
linux-a19bffb10c46744760e3c91cf6b5b58a998a4ba9.zip
accel/ivpu: Implement DCT handling
When host system is under heavy load and the NPU is already running on the lowest frequency, PUNIT may request Duty Cycle Throttling (DCT). This will further reduce NPU power usage. PUNIT requests DCT mode using Survabilty IRQ and mailbox register. The driver then issues a JSM message to the FW that enables the DCT mode. If the NPU resets while in DCT mode, the driver request DCT mode during FW boot. Also add debugfs "dct" file that allows to set arbitrary DCT percentage, which is used by driver tests. Signed-off-by: Jacek Lawrynowicz <jacek.lawrynowicz@linux.intel.com> Reviewed-by: Wachowski, Karol <karol.wachowski@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20240611120433.1012423-7-jacek.lawrynowicz@linux.intel.com
Diffstat (limited to 'drivers/accel/ivpu/ivpu_pm.c')
-rw-r--r--drivers/accel/ivpu/ivpu_pm.c67
1 files changed, 66 insertions, 1 deletions
diff --git a/drivers/accel/ivpu/ivpu_pm.c b/drivers/accel/ivpu/ivpu_pm.c
index 9d5f500afd20..602fa4e65c22 100644
--- a/drivers/accel/ivpu/ivpu_pm.c
+++ b/drivers/accel/ivpu/ivpu_pm.c
@@ -245,7 +245,7 @@ int ivpu_pm_runtime_suspend_cb(struct device *dev)
ivpu_dbg(vdev, PM, "Runtime suspend..\n");
- is_idle = ivpu_hw_is_idle(vdev);
+ is_idle = ivpu_hw_is_idle(vdev) || vdev->pm->dct_active_percent;
if (!is_idle)
ivpu_err(vdev, "NPU is not idle before autosuspend\n");
@@ -397,3 +397,68 @@ void ivpu_pm_disable(struct ivpu_device *vdev)
pm_runtime_get_noresume(vdev->drm.dev);
pm_runtime_forbid(vdev->drm.dev);
}
+
+int ivpu_pm_dct_init(struct ivpu_device *vdev)
+{
+ if (vdev->pm->dct_active_percent)
+ return ivpu_pm_dct_enable(vdev, vdev->pm->dct_active_percent);
+
+ return 0;
+}
+
+int ivpu_pm_dct_enable(struct ivpu_device *vdev, u8 active_percent)
+{
+ u32 active_us, inactive_us;
+ int ret;
+
+ if (active_percent == 0 || active_percent > 100)
+ return -EINVAL;
+
+ active_us = (DCT_PERIOD_US * active_percent) / 100;
+ inactive_us = DCT_PERIOD_US - active_us;
+
+ ret = ivpu_jsm_dct_enable(vdev, active_us, inactive_us);
+ if (ret) {
+ ivpu_err_ratelimited(vdev, "Filed to enable DCT: %d\n", ret);
+ return ret;
+ }
+
+ vdev->pm->dct_active_percent = active_percent;
+
+ ivpu_dbg(vdev, PM, "DCT set to %u%% (D0: %uus, D0i2: %uus)\n",
+ active_percent, active_us, inactive_us);
+ return 0;
+}
+
+int ivpu_pm_dct_disable(struct ivpu_device *vdev)
+{
+ int ret;
+
+ ret = ivpu_jsm_dct_disable(vdev);
+ if (ret) {
+ ivpu_err_ratelimited(vdev, "Filed to disable DCT: %d\n", ret);
+ return ret;
+ }
+
+ vdev->pm->dct_active_percent = 0;
+
+ ivpu_dbg(vdev, PM, "DCT disabled\n");
+ return 0;
+}
+
+void ivpu_pm_dct_irq_thread_handler(struct ivpu_device *vdev)
+{
+ bool enable;
+ int ret;
+
+ if (ivpu_hw_btrs_dct_get_request(vdev, &enable))
+ return;
+
+ if (vdev->pm->dct_active_percent)
+ ret = ivpu_pm_dct_enable(vdev, DCT_DEFAULT_ACTIVE_PERCENT);
+ else
+ ret = ivpu_pm_dct_disable(vdev);
+
+ if (!ret)
+ ivpu_hw_btrs_dct_set_status(vdev, enable, vdev->pm->dct_active_percent);
+}