diff options
| author | Jacek Lawrynowicz <jacek.lawrynowicz@linux.intel.com> | 2024-06-11 14:04:23 +0200 |
|---|---|---|
| committer | Jacek Lawrynowicz <jacek.lawrynowicz@linux.intel.com> | 2024-06-14 09:13:32 +0200 |
| commit | a19bffb10c46744760e3c91cf6b5b58a998a4ba9 (patch) | |
| tree | ebfcdc0f54fa0366fc0d045a938a7cb9b56446ff /drivers/accel/ivpu/ivpu_pm.c | |
| parent | ab4484cd863b3637ec8e03318532785476d12dfc (diff) | |
| download | linux-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.c | 67 |
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); +} |
