From: Andrzej Kacprowski <andrzej.kacprowski@linux.intel.com>
To: Maciej Falkowski <maciej.falkowski@linux.intel.com>,
dri-devel@lists.freedesktop.org
Cc: oded.gabbay@gmail.com, jeff.hugo@oss.qualcomm.com,
karol.wachowski@linux.intel.com, lizhi.hou@amd.com
Subject: Re: [PATCH] accel/ivpu: Implement warm boot flow for NPU6 and unify boot handling
Date: Wed, 7 Jan 2026 12:46:30 +0100 [thread overview]
Message-ID: <0eb54917-02cd-4dd6-a5fe-2599e1aab6a1@linux.intel.com> (raw)
In-Reply-To: <20251230142116.540026-1-maciej.falkowski@linux.intel.com>
Reviewed-by: Andrzej Kacprowski <andrzej.kacprowski@linux.intel.com>
On 12/30/2025 3:21 PM, Maciej Falkowski wrote:
> From: Karol Wachowski <karol.wachowski@linux.intel.com>
>
> Starting from NPU6, the driver can pass boot parameters address through
> the AON retention register and toggle between cold/warm boot types using
> the boot_type parameter, while setting the cold boot entry point in both
> cases.
>
> Refactor the existing cold/warm boot handling to be consistent with the
> new NPU6 boot flow requirements and still maintain compatibility with
> older boot flows.
>
> This will allow firmware to remove support for legacy warm boot starting
> from NPU6.
>
> Fixes: 550f4dd2cedd ("accel/ivpu: Add support for Nova Lake's NPU")
> Signed-off-by: Karol Wachowski <karol.wachowski@linux.intel.com>
> Signed-off-by: Maciej Falkowski <maciej.falkowski@linux.intel.com>
> ---
> drivers/accel/ivpu/ivpu_debugfs.c | 4 +-
> drivers/accel/ivpu/ivpu_drv.c | 4 +-
> drivers/accel/ivpu/ivpu_fw.c | 13 +++--
> drivers/accel/ivpu/ivpu_fw.h | 9 ++--
> drivers/accel/ivpu/ivpu_hw_40xx_reg.h | 6 +++
> drivers/accel/ivpu/ivpu_hw_ip.c | 74 ++++++++++++++++++---------
> drivers/accel/ivpu/ivpu_hw_ip.h | 1 -
> drivers/accel/ivpu/ivpu_pm.c | 13 +++--
> drivers/accel/ivpu/ivpu_pm.h | 1 -
> 9 files changed, 82 insertions(+), 43 deletions(-)
>
> diff --git a/drivers/accel/ivpu/ivpu_debugfs.c b/drivers/accel/ivpu/ivpu_debugfs.c
> index 3bd85ee6c26b..a09f54fc4302 100644
> --- a/drivers/accel/ivpu/ivpu_debugfs.c
> +++ b/drivers/accel/ivpu/ivpu_debugfs.c
> @@ -20,6 +20,7 @@
> #include "ivpu_hw.h"
> #include "ivpu_jsm_msg.h"
> #include "ivpu_pm.h"
> +#include "vpu_boot_api.h"
>
> static inline struct ivpu_device *seq_to_ivpu(struct seq_file *s)
> {
> @@ -96,7 +97,8 @@ static int last_bootmode_show(struct seq_file *s, void *v)
> {
> struct ivpu_device *vdev = seq_to_ivpu(s);
>
> - seq_printf(s, "%s\n", (vdev->pm->is_warmboot) ? "warmboot" : "coldboot");
> + seq_printf(s, "%s\n", (vdev->fw->last_boot_mode == VPU_BOOT_TYPE_WARMBOOT) ?
> + "warm boot" : "cold boot");
>
> return 0;
> }
> diff --git a/drivers/accel/ivpu/ivpu_drv.c b/drivers/accel/ivpu/ivpu_drv.c
> index 3d6fccdefdd6..8ffda57459df 100644
> --- a/drivers/accel/ivpu/ivpu_drv.c
> +++ b/drivers/accel/ivpu/ivpu_drv.c
> @@ -384,6 +384,7 @@ int ivpu_boot(struct ivpu_device *vdev)
> drm_WARN_ON(&vdev->drm, !xa_empty(&vdev->submitted_jobs_xa));
>
> ivpu_fw_boot_params_setup(vdev, ivpu_bo_vaddr(vdev->fw->mem_bp));
> + vdev->fw->last_boot_mode = vdev->fw->next_boot_mode;
>
> ret = ivpu_hw_boot_fw(vdev);
> if (ret) {
> @@ -396,13 +397,12 @@ int ivpu_boot(struct ivpu_device *vdev)
> ivpu_err(vdev, "Failed to boot the firmware: %d\n", ret);
> goto err_diagnose_failure;
> }
> -
> ivpu_hw_irq_clear(vdev);
> enable_irq(vdev->irq);
> ivpu_hw_irq_enable(vdev);
> ivpu_ipc_enable(vdev);
>
> - if (ivpu_fw_is_cold_boot(vdev)) {
> + if (!ivpu_fw_is_warm_boot(vdev)) {
> ret = ivpu_pm_dct_init(vdev);
> if (ret)
> goto err_disable_ipc;
> diff --git a/drivers/accel/ivpu/ivpu_fw.c b/drivers/accel/ivpu/ivpu_fw.c
> index 48386d2cddbb..107f8ad31050 100644
> --- a/drivers/accel/ivpu/ivpu_fw.c
> +++ b/drivers/accel/ivpu/ivpu_fw.c
> @@ -300,9 +300,7 @@ static int ivpu_fw_parse(struct ivpu_device *vdev)
> fw->image_load_offset = image_load_addr - runtime_addr;
> fw->image_size = image_size;
> fw->shave_nn_size = PAGE_ALIGN(fw_hdr->shave_nn_fw_size);
> -
> fw->cold_boot_entry_point = fw_hdr->entry_point;
> - fw->entry_point = fw->cold_boot_entry_point;
>
> fw->trace_level = min_t(u32, ivpu_fw_log_level, IVPU_FW_LOG_FATAL);
> fw->trace_destination_mask = VPU_TRACE_DESTINATION_VERBOSE_TRACING;
> @@ -338,7 +336,7 @@ static int ivpu_fw_parse(struct ivpu_device *vdev)
> fw->image_load_offset, fw->image_size);
> ivpu_dbg(vdev, FW_BOOT, "Read-only section: address 0x%llx, size %u\n",
> fw->read_only_addr, fw->read_only_size);
> - ivpu_dbg(vdev, FW_BOOT, "FW entry point: 0x%llx\n", fw->entry_point);
> + ivpu_dbg(vdev, FW_BOOT, "FW cold boot entry point: 0x%llx\n", fw->cold_boot_entry_point);
> ivpu_dbg(vdev, FW_BOOT, "SHAVE NN size: %u\n", fw->shave_nn_size);
>
> return 0;
> @@ -616,6 +614,7 @@ static void ivpu_fw_boot_params_print(struct ivpu_device *vdev, struct vpu_boot_
> boot_params->power_profile);
> ivpu_dbg(vdev, FW_BOOT, "boot_params.vpu_uses_ecc_mca_signal = 0x%x\n",
> boot_params->vpu_uses_ecc_mca_signal);
> + ivpu_dbg(vdev, FW_BOOT, "boot_params.boot_type = 0x%x\n", boot_params->boot_type);
> }
>
> void ivpu_fw_boot_params_setup(struct ivpu_device *vdev, struct vpu_boot_params *boot_params)
> @@ -623,7 +622,7 @@ void ivpu_fw_boot_params_setup(struct ivpu_device *vdev, struct vpu_boot_params
> struct ivpu_bo *ipc_mem_rx = vdev->ipc->mem_rx;
>
> /* In case of warm boot only update variable params */
> - if (!ivpu_fw_is_cold_boot(vdev)) {
> + if (ivpu_fw_is_warm_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;
> @@ -635,16 +634,16 @@ void ivpu_fw_boot_params_setup(struct ivpu_device *vdev, struct vpu_boot_params
> boot_params->d0i3_entry_vpu_ts);
> ivpu_dbg(vdev, FW_BOOT, "boot_params.system_time_us = %llu\n",
> boot_params->system_time_us);
> + ivpu_dbg(vdev, FW_BOOT, "boot_params.boot_type = 0x%x\n", boot_params->boot_type);
>
> boot_params->save_restore_ret_address = 0;
> - vdev->pm->is_warmboot = true;
> + boot_params->boot_type = VPU_BOOT_TYPE_WARMBOOT;
> wmb(); /* Flush WC buffers after writing save_restore_ret_address */
> return;
> }
>
> memset(boot_params, 0, sizeof(*boot_params));
> - vdev->pm->is_warmboot = false;
> -
> + boot_params->boot_type = VPU_BOOT_TYPE_COLDBOOT;
> boot_params->magic = VPU_BOOT_PARAMS_MAGIC;
> boot_params->vpu_id = to_pci_dev(vdev->drm.dev)->bus->number;
>
> diff --git a/drivers/accel/ivpu/ivpu_fw.h b/drivers/accel/ivpu/ivpu_fw.h
> index 00945892b55e..d3c410912c9c 100644
> --- a/drivers/accel/ivpu/ivpu_fw.h
> +++ b/drivers/accel/ivpu/ivpu_fw.h
> @@ -6,6 +6,7 @@
> #ifndef __IVPU_FW_H__
> #define __IVPU_FW_H__
>
> +#include "vpu_boot_api.h"
> #include "vpu_jsm_api.h"
>
> #define FW_VERSION_HEADER_SIZE SZ_4K
> @@ -34,8 +35,10 @@ struct ivpu_fw_info {
> u64 image_load_offset;
> u32 image_size;
> u32 shave_nn_size;
> - u64 entry_point; /* Cold or warm boot entry point for next boot */
> + u64 warm_boot_entry_point;
> u64 cold_boot_entry_point;
> + u8 last_boot_mode;
> + u8 next_boot_mode;
> u32 trace_level;
> u32 trace_destination_mask;
> u64 trace_hw_component_mask;
> @@ -54,9 +57,9 @@ void ivpu_fw_fini(struct ivpu_device *vdev);
> void ivpu_fw_load(struct ivpu_device *vdev);
> void ivpu_fw_boot_params_setup(struct ivpu_device *vdev, struct vpu_boot_params *boot_params);
>
> -static inline bool ivpu_fw_is_cold_boot(struct ivpu_device *vdev)
> +static inline bool ivpu_fw_is_warm_boot(struct ivpu_device *vdev)
> {
> - return vdev->fw->entry_point == vdev->fw->cold_boot_entry_point;
> + return vdev->fw->next_boot_mode == VPU_BOOT_TYPE_WARMBOOT;
> }
>
> static inline u32 ivpu_fw_preempt_buf_size(struct ivpu_device *vdev)
> diff --git a/drivers/accel/ivpu/ivpu_hw_40xx_reg.h b/drivers/accel/ivpu/ivpu_hw_40xx_reg.h
> index fc0ee8d637f9..421242acb184 100644
> --- a/drivers/accel/ivpu/ivpu_hw_40xx_reg.h
> +++ b/drivers/accel/ivpu/ivpu_hw_40xx_reg.h
> @@ -121,6 +121,12 @@
> #define VPU_50XX_HOST_SS_AON_PWR_ISLAND_STATUS_DLY 0x0003006cu
> #define VPU_50XX_HOST_SS_AON_PWR_ISLAND_STATUS_DLY_STATUS_DLY_MASK GENMASK(7, 0)
>
> +#define VPU_40XX_HOST_SS_AON_RETENTION0 0x0003000cu
> +#define VPU_40XX_HOST_SS_AON_RETENTION1 0x00030010u
> +#define VPU_40XX_HOST_SS_AON_RETENTION2 0x00030014u
> +#define VPU_40XX_HOST_SS_AON_RETENTION3 0x00030018u
> +#define VPU_40XX_HOST_SS_AON_RETENTION4 0x0003001cu
> +
> #define VPU_40XX_HOST_SS_AON_IDLE_GEN 0x00030200u
> #define VPU_40XX_HOST_SS_AON_IDLE_GEN_EN_MASK BIT_MASK(0)
> #define VPU_40XX_HOST_SS_AON_IDLE_GEN_HW_PG_EN_MASK BIT_MASK(1)
> diff --git a/drivers/accel/ivpu/ivpu_hw_ip.c b/drivers/accel/ivpu/ivpu_hw_ip.c
> index 06aa1e7dc50b..959984c54341 100644
> --- a/drivers/accel/ivpu/ivpu_hw_ip.c
> +++ b/drivers/accel/ivpu/ivpu_hw_ip.c
> @@ -5,6 +5,7 @@
>
> #include "ivpu_drv.h"
> #include "ivpu_fw.h"
> +#include "ivpu_gem.h"
> #include "ivpu_hw.h"
> #include "ivpu_hw_37xx_reg.h"
> #include "ivpu_hw_40xx_reg.h"
> @@ -816,6 +817,14 @@ void ivpu_hw_ip_tbu_mmu_enable(struct ivpu_device *vdev)
> return ivpu_hw_ip_tbu_mmu_enable_40xx(vdev);
> }
>
> +static inline u64 get_entry_point_addr(struct ivpu_device *vdev)
> +{
> + if (ivpu_fw_is_warm_boot(vdev))
> + return vdev->fw->warm_boot_entry_point;
> + else
> + return vdev->fw->cold_boot_entry_point;
> +}
> +
> static int soc_cpu_boot_37xx(struct ivpu_device *vdev)
> {
> u32 val;
> @@ -832,15 +841,12 @@ static int soc_cpu_boot_37xx(struct ivpu_device *vdev)
> val = REG_CLR_FLD(VPU_37XX_CPU_SS_MSSCPU_CPR_LEON_RT_VEC, IRQI_RESUME0, val);
> REGV_WR32(VPU_37XX_CPU_SS_MSSCPU_CPR_LEON_RT_VEC, val);
>
> - val = vdev->fw->entry_point >> 9;
> + val = get_entry_point_addr(vdev) >> 9;
> REGV_WR32(VPU_37XX_HOST_SS_LOADING_ADDRESS_LO, val);
>
> val = REG_SET_FLD(VPU_37XX_HOST_SS_LOADING_ADDRESS_LO, DONE, val);
> REGV_WR32(VPU_37XX_HOST_SS_LOADING_ADDRESS_LO, val);
>
> - ivpu_dbg(vdev, PM, "Booting firmware, mode: %s\n",
> - vdev->fw->entry_point == vdev->fw->cold_boot_entry_point ? "cold boot" : "resume");
> -
> return 0;
> }
>
> @@ -894,46 +900,68 @@ static int soc_cpu_drive_40xx(struct ivpu_device *vdev, bool enable)
> return ret;
> }
>
> -static int soc_cpu_enable(struct ivpu_device *vdev)
> +static void soc_cpu_set_entry_point_40xx(struct ivpu_device *vdev, u64 entry_point)
> {
> - if (ivpu_hw_ip_gen(vdev) >= IVPU_HW_IP_60XX)
> - return 0;
> + u64 val64;
> + u32 val;
> +
> + val64 = entry_point;
> + val64 <<= ffs(VPU_40XX_HOST_SS_VERIFICATION_ADDRESS_LO_IMAGE_LOCATION_MASK) - 1;
> + REGV_WR64(VPU_40XX_HOST_SS_VERIFICATION_ADDRESS_LO, val64);
>
> - return soc_cpu_drive_40xx(vdev, true);
> + val = REGV_RD32(VPU_40XX_HOST_SS_VERIFICATION_ADDRESS_LO);
> + val = REG_SET_FLD(VPU_40XX_HOST_SS_VERIFICATION_ADDRESS_LO, DONE, val);
> + REGV_WR32(VPU_40XX_HOST_SS_VERIFICATION_ADDRESS_LO, val);
> }
>
> static int soc_cpu_boot_40xx(struct ivpu_device *vdev)
> {
> int ret;
> - u32 val;
> - u64 val64;
>
> - ret = soc_cpu_enable(vdev);
> + ret = soc_cpu_drive_40xx(vdev, true);
> if (ret) {
> ivpu_err(vdev, "Failed to enable SOC CPU: %d\n", ret);
> return ret;
> }
>
> - val64 = vdev->fw->entry_point;
> - val64 <<= ffs(VPU_40XX_HOST_SS_VERIFICATION_ADDRESS_LO_IMAGE_LOCATION_MASK) - 1;
> - REGV_WR64(VPU_40XX_HOST_SS_VERIFICATION_ADDRESS_LO, val64);
> + soc_cpu_set_entry_point_40xx(vdev, get_entry_point_addr(vdev));
>
> - val = REGV_RD32(VPU_40XX_HOST_SS_VERIFICATION_ADDRESS_LO);
> - val = REG_SET_FLD(VPU_40XX_HOST_SS_VERIFICATION_ADDRESS_LO, DONE, val);
> - REGV_WR32(VPU_40XX_HOST_SS_VERIFICATION_ADDRESS_LO, val);
> + return 0;
> +}
>
> - ivpu_dbg(vdev, PM, "Booting firmware, mode: %s\n",
> - ivpu_fw_is_cold_boot(vdev) ? "cold boot" : "resume");
> +static int soc_cpu_boot_60xx(struct ivpu_device *vdev)
> +{
> + REGV_WR64(VPU_40XX_HOST_SS_AON_RETENTION1, vdev->fw->mem_bp->vpu_addr);
> + soc_cpu_set_entry_point_40xx(vdev, vdev->fw->cold_boot_entry_point);
>
> return 0;
> }
>
> int ivpu_hw_ip_soc_cpu_boot(struct ivpu_device *vdev)
> {
> - if (ivpu_hw_ip_gen(vdev) == IVPU_HW_IP_37XX)
> - return soc_cpu_boot_37xx(vdev);
> - else
> - return soc_cpu_boot_40xx(vdev);
> + int ret;
> +
> + switch (ivpu_hw_ip_gen(vdev)) {
> + case IVPU_HW_IP_37XX:
> + ret = soc_cpu_boot_37xx(vdev);
> + break;
> +
> + case IVPU_HW_IP_40XX:
> + case IVPU_HW_IP_50XX:
> + ret = soc_cpu_boot_40xx(vdev);
> + break;
> +
> + default:
> + ret = soc_cpu_boot_60xx(vdev);
> + }
> +
> + if (ret)
> + return ret;
> +
> + ivpu_dbg(vdev, PM, "Booting firmware, mode: %s\n",
> + ivpu_fw_is_warm_boot(vdev) ? "warm boot" : "cold boot");
> +
> + return 0;
> }
>
> static void wdt_disable_37xx(struct ivpu_device *vdev)
> diff --git a/drivers/accel/ivpu/ivpu_hw_ip.h b/drivers/accel/ivpu/ivpu_hw_ip.h
> index 5b1b391aa577..dbbcdd10a5f8 100644
> --- a/drivers/accel/ivpu/ivpu_hw_ip.h
> +++ b/drivers/accel/ivpu/ivpu_hw_ip.h
> @@ -29,7 +29,6 @@ u32 ivpu_hw_ip_ipc_rx_addr_get(struct ivpu_device *vdev);
> void ivpu_hw_ip_ipc_tx_set(struct ivpu_device *vdev, u32 vpu_addr);
> void ivpu_hw_ip_irq_enable(struct ivpu_device *vdev);
> void ivpu_hw_ip_irq_disable(struct ivpu_device *vdev);
> -void ivpu_hw_ip_diagnose_failure(struct ivpu_device *vdev);
> void ivpu_hw_ip_fabric_req_override_enable_50xx(struct ivpu_device *vdev);
> void ivpu_hw_ip_fabric_req_override_disable_50xx(struct ivpu_device *vdev);
>
> diff --git a/drivers/accel/ivpu/ivpu_pm.c b/drivers/accel/ivpu/ivpu_pm.c
> index 480c075d87f6..d20144a21e09 100644
> --- a/drivers/accel/ivpu/ivpu_pm.c
> +++ b/drivers/accel/ivpu/ivpu_pm.c
> @@ -47,8 +47,10 @@ static void ivpu_pm_prepare_cold_boot(struct ivpu_device *vdev)
> ivpu_ipc_reset(vdev);
> ivpu_fw_log_reset(vdev);
> ivpu_fw_load(vdev);
> - fw->entry_point = fw->cold_boot_entry_point;
> fw->last_heartbeat = 0;
> +
> + ivpu_dbg(vdev, FW_BOOT, "Cold boot entry point 0x%llx", vdev->fw->cold_boot_entry_point);
> + fw->next_boot_mode = VPU_BOOT_TYPE_COLDBOOT;
> }
>
> static void ivpu_pm_prepare_warm_boot(struct ivpu_device *vdev)
> @@ -56,13 +58,14 @@ static void ivpu_pm_prepare_warm_boot(struct ivpu_device *vdev)
> struct ivpu_fw_info *fw = vdev->fw;
> struct vpu_boot_params *bp = ivpu_bo_vaddr(fw->mem_bp);
>
> - if (!bp->save_restore_ret_address) {
> + fw->warm_boot_entry_point = bp->save_restore_ret_address;
> + if (!fw->warm_boot_entry_point) {
> ivpu_pm_prepare_cold_boot(vdev);
> return;
> }
>
> - ivpu_dbg(vdev, FW_BOOT, "Save/restore entry point %llx", bp->save_restore_ret_address);
> - fw->entry_point = bp->save_restore_ret_address;
> + ivpu_dbg(vdev, FW_BOOT, "Warm boot entry point 0x%llx", fw->warm_boot_entry_point);
> + fw->next_boot_mode = VPU_BOOT_TYPE_WARMBOOT;
> }
>
> static int ivpu_suspend(struct ivpu_device *vdev)
> @@ -110,7 +113,7 @@ static int ivpu_resume(struct ivpu_device *vdev)
> ivpu_hw_power_down(vdev);
> pci_set_power_state(to_pci_dev(vdev->drm.dev), PCI_D3hot);
>
> - if (!ivpu_fw_is_cold_boot(vdev)) {
> + if (ivpu_fw_is_warm_boot(vdev)) {
> ivpu_pm_prepare_cold_boot(vdev);
> goto retry;
> } else {
> diff --git a/drivers/accel/ivpu/ivpu_pm.h b/drivers/accel/ivpu/ivpu_pm.h
> index a2aa7a27f32e..00f2a01e3df6 100644
> --- a/drivers/accel/ivpu/ivpu_pm.h
> +++ b/drivers/accel/ivpu/ivpu_pm.h
> @@ -18,7 +18,6 @@ struct ivpu_pm_info {
> struct rw_semaphore reset_lock;
> atomic_t reset_counter;
> atomic_t reset_pending;
> - bool is_warmboot;
> u8 dct_active_percent;
> };
>
next prev parent reply other threads:[~2026-01-07 11:46 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-12-30 14:21 [PATCH] accel/ivpu: Implement warm boot flow for NPU6 and unify boot handling Maciej Falkowski
2026-01-07 11:46 ` Andrzej Kacprowski [this message]
2026-01-07 17:11 ` Jeff Hugo
2026-01-08 11:37 ` Falkowski, Maciej
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=0eb54917-02cd-4dd6-a5fe-2599e1aab6a1@linux.intel.com \
--to=andrzej.kacprowski@linux.intel.com \
--cc=dri-devel@lists.freedesktop.org \
--cc=jeff.hugo@oss.qualcomm.com \
--cc=karol.wachowski@linux.intel.com \
--cc=lizhi.hou@amd.com \
--cc=maciej.falkowski@linux.intel.com \
--cc=oded.gabbay@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox