accel/ivpu: Pass D0i3 residency time to the VPU firmware
authorAndrzej Kacprowski <andrzej.kacprowski@linux.intel.com>
Sat, 28 Oct 2023 13:34:12 +0000 (15:34 +0200)
committerStanislaw Gruszka <stanislaw.gruszka@linux.intel.com>
Mon, 30 Oct 2023 10:06:12 +0000 (11:06 +0100)
The firmware needs to know the time spent in D0i3/D3 to
calculate telemetry data. The D0i3/D3 residency time is
calculated by the driver and passed to the firmware
in the boot parameters.

The driver also passes VPU perf counter value captured
right before entering D0i3 - this allows the VPU firmware
to generate monotonic timestamps for the logs.

Signed-off-by: Andrzej Kacprowski <andrzej.kacprowski@linux.intel.com>
Reviewed-by: Stanislaw Gruszka <stanislaw.gruszka@linux.intel.com>
Reviewed-by: Jeffrey Hugo <quic_jhugo@quicinc.com>
Signed-off-by: Stanislaw Gruszka <stanislaw.gruszka@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20231028133415.1169975-9-stanislaw.gruszka@linux.intel.com
drivers/accel/ivpu/ivpu_fw.c
drivers/accel/ivpu/ivpu_hw.h
drivers/accel/ivpu/ivpu_hw_37xx.c
drivers/accel/ivpu/ivpu_hw_37xx_reg.h

index b81827540db94b8467173a28a54160af8ad71c90..383e4d9b97c85e6e8a20f687b1cbbfe00c603cdc 100644 (file)
@@ -426,14 +426,27 @@ static void ivpu_fw_boot_params_print(struct ivpu_device *vdev, struct vpu_boot_
                 boot_params->vpu_telemetry_enable);
        ivpu_dbg(vdev, FW_BOOT, "boot_params.dvfs_mode = %u\n",
                 boot_params->dvfs_mode);
+       ivpu_dbg(vdev, FW_BOOT, "boot_params.d0i3_residency_time_us = %lld\n",
+                boot_params->d0i3_residency_time_us);
+       ivpu_dbg(vdev, FW_BOOT, "boot_params.d0i3_entry_vpu_ts = %llu\n",
+                boot_params->d0i3_entry_vpu_ts);
 }
 
 void ivpu_fw_boot_params_setup(struct ivpu_device *vdev, struct vpu_boot_params *boot_params)
 {
        struct ivpu_bo *ipc_mem_rx = vdev->ipc->mem_rx;
 
-       /* In case of warm boot we only have to reset the entrypoint addr */
+       /* In case of warm boot only update variable params */
        if (!ivpu_fw_is_cold_boot(vdev)) {
+               boot_params->d0i3_residency_time_us =
+                       ktime_us_delta(ktime_get_boottime(), vdev->hw->d0i3_entry_host_ts);
+               boot_params->d0i3_entry_vpu_ts = vdev->hw->d0i3_entry_vpu_ts;
+
+               ivpu_dbg(vdev, FW_BOOT, "boot_params.d0i3_residency_time_us = %lld\n",
+                        boot_params->d0i3_residency_time_us);
+               ivpu_dbg(vdev, FW_BOOT, "boot_params.d0i3_entry_vpu_ts = %llu\n",
+                        boot_params->d0i3_entry_vpu_ts);
+
                boot_params->save_restore_ret_address = 0;
                vdev->pm->is_warmboot = true;
                return;
@@ -497,6 +510,8 @@ void ivpu_fw_boot_params_setup(struct ivpu_device *vdev, struct vpu_boot_params
        boot_params->punit_telemetry_sram_size = ivpu_hw_reg_telemetry_size_get(vdev);
        boot_params->vpu_telemetry_enable = ivpu_hw_reg_telemetry_enable_get(vdev);
        boot_params->dvfs_mode = vdev->fw->dvfs_mode;
+       boot_params->d0i3_residency_time_us = 0;
+       boot_params->d0i3_entry_vpu_ts = 0;
 
        wmb(); /* Flush WC buffers after writing bootparams */
 
index ab341237bcf97a45608d35f965e4d3e2895f91e5..fd4809b56168fe5d9c0e67b3de7ffe9d16715d27 100644 (file)
@@ -57,6 +57,8 @@ struct ivpu_hw_info {
        u32 sku;
        u16 config;
        int dma_bits;
+       ktime_t d0i3_entry_host_ts;
+       u64 d0i3_entry_vpu_ts;
 };
 
 extern const struct ivpu_hw_ops ivpu_hw_37xx_ops;
index 8340c84ed6dea595d1e5fa69aed270fd1d60d2dd..451c9777b237b392f960f63435e1027a85506865 100644 (file)
@@ -714,10 +714,18 @@ static bool ivpu_hw_37xx_is_idle(struct ivpu_device *vdev)
               REG_TEST_FLD(VPU_37XX_BUTTRESS_VPU_STATUS, IDLE, val);
 }
 
+static void ivpu_hw_37xx_save_d0i3_entry_timestamp(struct ivpu_device *vdev)
+{
+       vdev->hw->d0i3_entry_host_ts = ktime_get_boottime();
+       vdev->hw->d0i3_entry_vpu_ts = REGV_RD64(VPU_37XX_CPU_SS_TIM_PERF_FREE_CNT);
+}
+
 static int ivpu_hw_37xx_power_down(struct ivpu_device *vdev)
 {
        int ret = 0;
 
+       ivpu_hw_37xx_save_d0i3_entry_timestamp(vdev);
+
        if (!ivpu_hw_37xx_is_idle(vdev) && ivpu_hw_37xx_reset(vdev))
                ivpu_err(vdev, "Failed to reset the VPU\n");
 
index 4083beb5e9dbabd2a1afe10b97a31faced1e8f3a..f6fec19192020ce07870868b8a045f775ce74fef 100644 (file)
 #define VPU_37XX_CPU_SS_TIM_GEN_CONFIG                                 0x06021008u
 #define VPU_37XX_CPU_SS_TIM_GEN_CONFIG_WDOG_TO_INT_CLR_MASK            BIT_MASK(9)
 
+#define VPU_37XX_CPU_SS_TIM_PERF_FREE_CNT                              0x06029000u
+
 #define VPU_37XX_CPU_SS_DOORBELL_0                                     0x06300000u
 #define VPU_37XX_CPU_SS_DOORBELL_0_SET_MASK                            BIT_MASK(0)