[PATCH 05/11] drm/msm/mdp5: unwind a failed mdp5_kms_init()

From: Dmitry Baryshkov

Date: Fri Oct 02 2026 - 20:28:48 EST


mdp5_kms_init() returns straight away when one of its later steps fails,
leaving behind the kms, the runtime PM reference taken around the address
space setup and the address space itself, and lets the ->destroy()
callback, which the caller runs afterwards, clean up. When mdp5_init()
fails, however, it has already run mdp5_destroy() itself, and ->destroy()
runs it a second time: the global state object is finalised twice.

Undo the steps which have completed, in the reverse order, drop the
runtime PM reference on the error path as well, and tell the caller not
to run ->destroy() after a failed init. Fold the hardware setup, which
can't fail, into mdp5_kms_init().

Fixes: 8d58ef346f30 ("drm/msm/mdp5: Add global state as a private atomic object")
Assisted-by: LLM
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@xxxxxxxxxxxxxxxx>
---
drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c | 44 ++++++++++++++++++++------------
1 file changed, 27 insertions(+), 17 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c
index 3934cd060b27..8fc8cdcf7d8c 100644
--- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c
+++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c
@@ -19,9 +19,8 @@
#include "msm_mmu.h"
#include "mdp5_kms.h"

-static int mdp5_hw_init(struct msm_kms *kms)
+static void mdp5_hw_init(struct mdp5_kms *mdp5_kms)
{
- struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
struct device *dev = &mdp5_kms->pdev->dev;
unsigned long flags;

@@ -58,8 +57,6 @@ static int mdp5_hw_init(struct msm_kms *kms)
mdp5_ctlm_hw_reset(mdp5_kms->ctlm);

pm_runtime_put_sync(dev);
-
- return 0;
}

/* Global/shared object state funcs */
@@ -198,24 +195,25 @@ static void mdp5_complete_commit(struct msm_kms *kms, unsigned crtc_mask)

static void mdp5_destroy(struct mdp5_kms *mdp5_kms);

-static void mdp5_kms_destroy(struct msm_kms *kms)
+static void mdp5_kms_destroy_vm(struct msm_kms *kms)
{
- struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
+ struct msm_mmu *mmu = to_msm_vm(kms->vm)->mmu;

- if (kms->vm) {
- struct msm_mmu *mmu = to_msm_vm(kms->vm)->mmu;
+ mmu->funcs->detach(mmu);
+ drm_gpuvm_put(kms->vm);
+}

- mmu->funcs->detach(mmu);
- drm_gpuvm_put(kms->vm);
- }
+static void mdp5_kms_destroy(struct msm_kms *kms)
+{
+ struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));

+ mdp5_kms_destroy_vm(kms);
mdp_kms_destroy(&mdp5_kms->base);
mdp5_destroy(mdp5_kms);
}

static const struct mdp_kms_funcs kms_funcs = {
.base = {
- .hw_init = mdp5_hw_init,
.irq_preinstall = mdp5_irq_preinstall,
.irq_postinstall = mdp5_irq_postinstall,
.irq_uninstall = mdp5_irq_uninstall,
@@ -506,6 +504,8 @@ static int mdp5_kms_init(struct drm_device *dev)
struct drm_gpuvm *vm;
int i, ret;

+ kms->init_unwinds = true;
+
ret = mdp5_init(to_platform_device(dev->dev), dev);
if (ret)
return ret;
@@ -517,7 +517,7 @@ static int mdp5_kms_init(struct drm_device *dev)
ret = mdp_kms_init(&mdp5_kms->base, &kms_funcs);
if (ret) {
DRM_DEV_ERROR(&pdev->dev, "failed to init kms\n");
- return ret;
+ goto err_mdp5_destroy;
}

config = mdp5_cfg_get_config(mdp5_kms->cfg);
@@ -538,19 +538,18 @@ static int mdp5_kms_init(struct drm_device *dev)
mdelay(16);

vm = msm_kms_init_vm(mdp5_kms->dev, pdev->dev.parent);
+ pm_runtime_put_sync(&pdev->dev);
if (IS_ERR(vm)) {
ret = PTR_ERR(vm);
- return ret;
+ goto err_kms_destroy;
}

kms->vm = vm;

- pm_runtime_put_sync(&pdev->dev);
-
ret = modeset_init(mdp5_kms);
if (ret) {
DRM_DEV_ERROR(&pdev->dev, "modeset_init failed: %d\n", ret);
- return ret;
+ goto err_destroy_vm;
}

dev->mode_config.min_width = 0;
@@ -561,7 +560,18 @@ static int mdp5_kms_init(struct drm_device *dev)
dev->max_vblank_count = 0; /* max_vblank_count is set on each CRTC */
dev->vblank_disable_immediate = true;

+ mdp5_hw_init(mdp5_kms);
+
return 0;
+
+err_destroy_vm:
+ mdp5_kms_destroy_vm(kms);
+err_kms_destroy:
+ mdp_kms_destroy(&mdp5_kms->base);
+err_mdp5_destroy:
+ mdp5_destroy(mdp5_kms);
+
+ return ret;
}

static void mdp5_destroy(struct mdp5_kms *mdp5_kms)

--
2.47.3