[PATCH] media: iris: Unload the firmware before hibernation

From: Abel Vesa

Date: Mon Oct 26 2026 - 09:47:45 EST


A hibernation image is restored after a power cycle, by a kernel that
may have loaded the firmware itself. Neither the firmware, which lives
in memory the image does not hold, nor its authentication by the
TrustZone survive that, so resuming the core from the restored kernel
fails:

qcom-iris aa00000.video-codec: failed to resume

Make sure the image does not hold an initialized core. Unload the
firmware before the image is created, and before the kernel that loads
the image jumps into it, so that the next session loads it again. Keep
the system error handler disabled meanwhile, so that it cannot load the
firmware again behind our back.

Refuse to hibernate while the device is open, as its sessions cannot
survive this. Failing them the way a system error does would let
hibernation go on, but would break every open file handle on each
hibernation, without userspace having a chance to tear the session
down cleanly.

Signed-off-by: Abel Vesa <abel.vesa@xxxxxxxxxxxxxxxx>
---
Prepared with help from an LLM-based assistant.
---
drivers/media/platform/qcom/iris/iris_probe.c | 44 +++++++++++++++++++++++++--
1 file changed, 42 insertions(+), 2 deletions(-)

diff --git a/drivers/media/platform/qcom/iris/iris_probe.c b/drivers/media/platform/qcom/iris/iris_probe.c
index 41dec90f3e2b..ea77c573b333 100644
--- a/drivers/media/platform/qcom/iris/iris_probe.c
+++ b/drivers/media/platform/qcom/iris/iris_probe.c
@@ -411,9 +411,49 @@ static int __maybe_unused iris_pm_resume(struct device *dev)
return ret;
}

+/*
+ * Neither the firmware nor its TrustZone authentication survive hibernation,
+ * so do not let the image hold an initialized core.
+ */
+static int iris_pm_freeze(struct device *dev)
+{
+ struct iris_core *core = dev_get_drvdata(dev);
+ int ret;
+
+ scoped_guard(mutex, &core->lock) {
+ if (!list_empty(&core->instances)) {
+ dev_err(dev, "cannot hibernate while the device is open\n");
+ return -EBUSY;
+ }
+ }
+
+ /* Keep a system error from loading the firmware again */
+ disable_delayed_work_sync(&core->sys_error_handler);
+ iris_core_deinit(core);
+
+ ret = pm_runtime_force_suspend(dev);
+ if (ret)
+ enable_delayed_work(&core->sys_error_handler);
+
+ return ret;
+}
+
+static int iris_pm_thaw(struct device *dev)
+{
+ struct iris_core *core = dev_get_drvdata(dev);
+
+ enable_delayed_work(&core->sys_error_handler);
+
+ return pm_runtime_force_resume(dev);
+}
+
static const struct dev_pm_ops iris_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
- pm_runtime_force_resume)
+ .suspend = pm_sleep_ptr(pm_runtime_force_suspend),
+ .resume = pm_sleep_ptr(pm_runtime_force_resume),
+ .freeze = pm_sleep_ptr(iris_pm_freeze),
+ .thaw = pm_sleep_ptr(iris_pm_thaw),
+ .poweroff = pm_sleep_ptr(pm_runtime_force_suspend),
+ .restore = pm_sleep_ptr(iris_pm_thaw),
SET_RUNTIME_PM_OPS(iris_pm_suspend, iris_pm_resume, NULL)
};


---
base-commit: 20a33c6b6cbe7e4805dfb6cd68816937443aa148
change-id: 20261023-b4-media-iris-unload-firmware-hibernation-930a88ecbe08

Best regards,
--
Abel Vesa <abel.vesa@xxxxxxxxxxxxxxxx>