From nobody Sun Feb 8 00:38:55 2026 Received: from smtpout-04.galae.net (smtpout-04.galae.net [185.171.202.116]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 63C0D337699 for ; Fri, 23 Jan 2026 16:13:38 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.171.202.116 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769184820; cv=none; b=NZW2plQxv8Pnu+7hj5rJoUZffkvb3HBN64ceddq/RNI3CoxYR0qgon1mZgskvjzEtsI4GjBWtKyx0KHnWDiHPAKAeglvaS7lnOCeblW3Jt1RSEdJZ03xbfhzHoMqfG6Bg4RuLCkxGbQQ8tiinOTo6RWkqx5jqZXAxak8lKWOjhw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769184820; c=relaxed/simple; bh=TxCjOgZfz5TrFAoiXe9s6ia27K1PEDdmSGgTe5XjVFE=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=aRvNn0KJ61f3GUXsFMDwfOI56KdyMvl21VJ9QlRYpjNowKMMJoNuxIZrB3ShYS22DJkgHU+Shvf3AP6ZeDgzPQAarbXFBzGGjYujCwMUnBriNw9VFXgtm1ABPziPn2xIOmnTi71A5XLvgAiKcML4thLJzLjZs26tQlhXhp7edxU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com; spf=pass smtp.mailfrom=bootlin.com; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b=azRDowmC; arc=none smtp.client-ip=185.171.202.116 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bootlin.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b="azRDowmC" Received: from smtpout-01.galae.net (smtpout-01.galae.net [212.83.139.233]) by smtpout-04.galae.net (Postfix) with ESMTPS id 224F5C1F1CA; Fri, 23 Jan 2026 16:13:37 +0000 (UTC) Received: from mail.galae.net (mail.galae.net [212.83.136.155]) by smtpout-01.galae.net (Postfix) with ESMTPS id C87706070A; Fri, 23 Jan 2026 16:13:36 +0000 (UTC) Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id 21AB0119A87A9; Fri, 23 Jan 2026 17:13:32 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=dkim; t=1769184815; h=from:subject:date:message-id:to:cc:mime-version:content-type: content-transfer-encoding:in-reply-to:references; bh=uk9c0AHNLUSQV7sMdQMvJLvTXEwq4+ucsFMx/IHfFwY=; b=azRDowmCFKD8RhBp2f6HKX27bKUEqC6XnhNj/O2RLEtIiuVhcgEluAYO0k0D/8sxVlt1ds TNxdb4zE9dwCBTlh0xz6NM3p/05DxEJo6byMIE+f0MLfDvZZmHbt4JDLQU94WktO83ZcBs 7DtIOh0imAW4qSxoDI5VN/lBAaR7gzdtuKlAwLI15Mz9vC0ZLxtsiPRbIR5joWaHYhc1nQ BsXdQFS+sZ1H/youj8vy6j87xYKbd8VTWwOGFpG+LrFiK+dFggVmI2wYB59tyqsoIcLmpY w9J4nVr9OnRmwyL5nZeidsmhZVRN27A3U6RO7N+rCpneUtyfeowdWz72+24fbw== From: "Kory Maincent (TI.com)" Date: Fri, 23 Jan 2026 17:12:36 +0100 Subject: [PATCH v5 18/25] drm/tilcdc: Convert to DRM managed resources Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260123-feature_tilcdc-v5-18-5a44d2aa3f6f@bootlin.com> References: <20260123-feature_tilcdc-v5-0-5a44d2aa3f6f@bootlin.com> In-Reply-To: <20260123-feature_tilcdc-v5-0-5a44d2aa3f6f@bootlin.com> To: Jyri Sarha , Tomi Valkeinen , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , David Airlie , Simona Vetter , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Russell King , Bartosz Golaszewski , Tony Lindgren , Andrzej Hajda , Neil Armstrong , Robert Foss , Laurent Pinchart , Jonas Karlman , Jernej Skrabec Cc: Markus Schneider-Pargmann , Bajjuri Praneeth , Luca Ceresoli , Louis Chauvet , Thomas Petazzoni , Miguel Gazquez , Herve Codina , dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-omap@vger.kernel.org, "Kory Maincent (TI.com)" X-Mailer: b4 0.15-dev-47773 X-Last-TLS-Session-Version: TLSv1.3 Convert the tilcdc driver to use DRM managed resources (drmm_* APIs) to eliminate resource lifetime issues, particularly in probe deferral scenarios. This conversion addresses potential use-after-free bugs by ensuring proper cleanup ordering through the DRM managed resource framework. The changes include: - Replace drm_crtc_init_with_planes() with drmm_crtc_alloc_with_planes() - Replace drm_universal_plane_init() with drmm_universal_plane_alloc() - Replace drm_simple_encoder_init() with drmm_simple_encoder_alloc() - Remove manual cleanup in tilcdc_crtc_destroy() and error paths - Remove drm_encoder_cleanup() from encoder error handling paths - Use drmm_add_action_or_reset() for remaining cleanup operations This approach is recommended by the DRM subsystem for improved resource lifetime management and is particularly important for drivers that may experience probe deferral. Reviewed-by: Luca Ceresoli Signed-off-by: Kory Maincent (TI.com) --- Change in v5: - Move drmm_add_action_or_reset() up to avoid missing cleanup in case of dmam_alloc_coherent() returning an error. Change in v4: - New patch. - Move on to DRM managed resources to fix null pointer dereference koops in case drm_of_find_panel_or_bridge() return EPROBE_DEFER. --- drivers/gpu/drm/tilcdc/tilcdc_crtc.c | 55 +++++++++++++++++------------= ---- drivers/gpu/drm/tilcdc/tilcdc_drv.c | 5 +-- drivers/gpu/drm/tilcdc/tilcdc_drv.h | 13 ++++++-- drivers/gpu/drm/tilcdc/tilcdc_encoder.c | 38 ++++++++--------------- drivers/gpu/drm/tilcdc/tilcdc_plane.c | 27 +++++++--------- 5 files changed, 64 insertions(+), 74 deletions(-) diff --git a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c b/drivers/gpu/drm/tilcdc/= tilcdc_crtc.c index 0bd99a2efeeb4..2916de3dce91e 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -30,7 +31,7 @@ struct tilcdc_crtc { struct drm_crtc base; =20 - struct drm_plane primary; + struct tilcdc_plane *primary; struct drm_pending_vblank_event *event; struct mutex enable_lock; bool enabled; @@ -555,16 +556,15 @@ static void tilcdc_crtc_recover_work(struct work_stru= ct *work) drm_modeset_unlock(&crtc->mutex); } =20 -void tilcdc_crtc_destroy(struct drm_crtc *crtc) +static void tilcdc_crtc_destroy(struct drm_device *dev, void *data) { - struct tilcdc_drm_private *priv =3D ddev_to_tilcdc_priv(crtc->dev); + struct tilcdc_drm_private *priv =3D (struct tilcdc_drm_private *)data; =20 - tilcdc_crtc_shutdown(crtc); + tilcdc_crtc_shutdown(priv->crtc); =20 flush_workqueue(priv->wq); =20 - of_node_put(crtc->port); - drm_crtc_cleanup(crtc); + of_node_put(priv->crtc->port); } =20 int tilcdc_crtc_update_fb(struct drm_crtc *crtc, @@ -714,7 +714,6 @@ static void tilcdc_crtc_reset(struct drm_crtc *crtc) } =20 static const struct drm_crtc_funcs tilcdc_crtc_funcs =3D { - .destroy =3D tilcdc_crtc_destroy, .set_config =3D drm_atomic_helper_set_config, .page_flip =3D drm_atomic_helper_page_flip, .reset =3D tilcdc_crtc_reset, @@ -960,12 +959,31 @@ int tilcdc_crtc_create(struct drm_device *dev) { struct tilcdc_drm_private *priv =3D ddev_to_tilcdc_priv(dev); struct tilcdc_crtc *tilcdc_crtc; + struct tilcdc_plane *primary; struct drm_crtc *crtc; int ret; =20 - tilcdc_crtc =3D devm_kzalloc(dev->dev, sizeof(*tilcdc_crtc), GFP_KERNEL); - if (!tilcdc_crtc) - return -ENOMEM; + primary =3D tilcdc_plane_init(dev); + if (IS_ERR(primary)) { + dev_err(dev->dev, "Failed to initialize plane: %pe\n", primary); + return PTR_ERR(primary); + } + + tilcdc_crtc =3D drmm_crtc_alloc_with_planes(dev, struct tilcdc_crtc, base, + &primary->base, + NULL, + &tilcdc_crtc_funcs, + "tilcdc crtc"); + if (IS_ERR(tilcdc_crtc)) { + dev_err(dev->dev, "Failed to init CRTC: %pe\n", tilcdc_crtc); + return PTR_ERR(tilcdc_crtc); + } + + tilcdc_crtc->primary =3D primary; + priv->crtc =3D &tilcdc_crtc->base; + ret =3D drmm_add_action_or_reset(dev, tilcdc_crtc_destroy, priv); + if (ret) + return ret; =20 init_completion(&tilcdc_crtc->palette_loaded); tilcdc_crtc->palette_base =3D dmam_alloc_coherent(dev->dev, @@ -978,10 +996,6 @@ int tilcdc_crtc_create(struct drm_device *dev) =20 crtc =3D &tilcdc_crtc->base; =20 - ret =3D tilcdc_plane_init(dev, &tilcdc_crtc->primary); - if (ret < 0) - goto fail; - mutex_init(&tilcdc_crtc->enable_lock); =20 init_waitqueue_head(&tilcdc_crtc->frame_done_wq); @@ -989,20 +1003,7 @@ int tilcdc_crtc_create(struct drm_device *dev) spin_lock_init(&tilcdc_crtc->irq_lock); INIT_WORK(&tilcdc_crtc->recover_work, tilcdc_crtc_recover_work); =20 - ret =3D drm_crtc_init_with_planes(dev, crtc, - &tilcdc_crtc->primary, - NULL, - &tilcdc_crtc_funcs, - "tilcdc crtc"); - if (ret < 0) - goto fail; - drm_crtc_helper_add(crtc, &tilcdc_crtc_helper_funcs); =20 - priv->crtc =3D crtc; return 0; - -fail: - tilcdc_crtc_destroy(crtc); - return ret; } diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/t= ilcdc_drv.c index 1a238a22309f4..3b11d296a7e91 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c @@ -392,7 +392,7 @@ static int tilcdc_pdev_probe(struct platform_device *pd= ev) if (ret) { dev_err(dev, "failed to register cpufreq notifier\n"); priv->freq_transition.notifier_call =3D NULL; - goto destroy_crtc; + goto disable_pm; } #endif =20 @@ -442,9 +442,7 @@ static int tilcdc_pdev_probe(struct platform_device *pd= ev) #ifdef CONFIG_CPU_FREQ cpufreq_unregister_notifier(&priv->freq_transition, CPUFREQ_TRANSITION_NOTIFIER); -destroy_crtc: #endif - tilcdc_crtc_destroy(priv->crtc); disable_pm: pm_runtime_disable(dev); clk_put(priv->clk); @@ -466,7 +464,6 @@ static void tilcdc_pdev_remove(struct platform_device *= pdev) cpufreq_unregister_notifier(&priv->freq_transition, CPUFREQ_TRANSITION_NOTIFIER); #endif - tilcdc_crtc_destroy(priv->crtc); pm_runtime_disable(&pdev->dev); clk_put(priv->clk); destroy_workqueue(priv->wq); diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.h b/drivers/gpu/drm/tilcdc/t= ilcdc_drv.h index c69e279a2539d..17d152f9f0b69 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_drv.h +++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.h @@ -77,7 +77,7 @@ struct tilcdc_drm_private { =20 struct drm_crtc *crtc; =20 - struct drm_encoder *encoder; + struct tilcdc_encoder *encoder; struct drm_connector *connector; =20 bool irq_enabled; @@ -91,11 +91,18 @@ int tilcdc_crtc_create(struct drm_device *dev); irqreturn_t tilcdc_crtc_irq(struct drm_crtc *crtc); void tilcdc_crtc_update_clk(struct drm_crtc *crtc); void tilcdc_crtc_shutdown(struct drm_crtc *crtc); -void tilcdc_crtc_destroy(struct drm_crtc *crtc); int tilcdc_crtc_update_fb(struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_pending_vblank_event *event); =20 -int tilcdc_plane_init(struct drm_device *dev, struct drm_plane *plane); +struct tilcdc_plane { + struct drm_plane base; +}; + +struct tilcdc_encoder { + struct drm_encoder base; +}; + +struct tilcdc_plane *tilcdc_plane_init(struct drm_device *dev); =20 #endif /* __TILCDC_DRV_H__ */ diff --git a/drivers/gpu/drm/tilcdc/tilcdc_encoder.c b/drivers/gpu/drm/tilc= dc/tilcdc_encoder.c index d42be3e16c536..1ee5761757a8c 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_encoder.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_encoder.c @@ -37,13 +37,13 @@ int tilcdc_attach_bridge(struct drm_device *ddev, struc= t drm_bridge *bridge) struct tilcdc_drm_private *priv =3D ddev_to_tilcdc_priv(ddev); int ret; =20 - priv->encoder->possible_crtcs =3D BIT(0); + priv->encoder->base.possible_crtcs =3D BIT(0); =20 - ret =3D drm_bridge_attach(priv->encoder, bridge, NULL, 0); + ret =3D drm_bridge_attach(&priv->encoder->base, bridge, NULL, 0); if (ret) return ret; =20 - priv->connector =3D tilcdc_encoder_find_connector(ddev, priv->encoder); + priv->connector =3D tilcdc_encoder_find_connector(ddev, &priv->encoder->b= ase); if (!priv->connector) return -ENODEV; =20 @@ -53,6 +53,7 @@ int tilcdc_attach_bridge(struct drm_device *ddev, struct = drm_bridge *bridge) int tilcdc_encoder_create(struct drm_device *ddev) { struct tilcdc_drm_private *priv =3D ddev_to_tilcdc_priv(ddev); + struct tilcdc_encoder *encoder; struct drm_bridge *bridge; struct drm_panel *panel; int ret; @@ -64,33 +65,20 @@ int tilcdc_encoder_create(struct drm_device *ddev) else if (ret) return ret; =20 - priv->encoder =3D devm_kzalloc(ddev->dev, sizeof(*priv->encoder), GFP_KER= NEL); - if (!priv->encoder) - return -ENOMEM; - - ret =3D drm_simple_encoder_init(ddev, priv->encoder, - DRM_MODE_ENCODER_NONE); - if (ret) { - dev_err(ddev->dev, "drm_encoder_init() failed %d\n", ret); - return ret; + encoder =3D drmm_simple_encoder_alloc(ddev, struct tilcdc_encoder, + base, DRM_MODE_ENCODER_NONE); + if (IS_ERR(encoder)) { + dev_err(ddev->dev, "drm_encoder_init() failed %pe\n", encoder); + return PTR_ERR(encoder); } + priv->encoder =3D encoder; =20 if (panel) { bridge =3D devm_drm_panel_bridge_add_typed(ddev->dev, panel, DRM_MODE_CONNECTOR_DPI); - if (IS_ERR(bridge)) { - ret =3D PTR_ERR(bridge); - goto err_encoder_cleanup; - } + if (IS_ERR(bridge)) + return PTR_ERR(bridge); } =20 - ret =3D tilcdc_attach_bridge(ddev, bridge); - if (ret) - goto err_encoder_cleanup; - - return 0; - -err_encoder_cleanup: - drm_encoder_cleanup(priv->encoder); - return ret; + return tilcdc_attach_bridge(ddev, bridge); } diff --git a/drivers/gpu/drm/tilcdc/tilcdc_plane.c b/drivers/gpu/drm/tilcdc= /tilcdc_plane.c index a77a5b22ebd96..d98a1ae0e31f8 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_plane.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_plane.c @@ -14,7 +14,6 @@ static const struct drm_plane_funcs tilcdc_plane_funcs =3D { .update_plane =3D drm_atomic_helper_update_plane, .disable_plane =3D drm_atomic_helper_disable_plane, - .destroy =3D drm_plane_cleanup, .reset =3D drm_atomic_helper_plane_reset, .atomic_duplicate_state =3D drm_atomic_helper_plane_duplicate_state, .atomic_destroy_state =3D drm_atomic_helper_plane_destroy_state, @@ -98,22 +97,20 @@ static const struct drm_plane_helper_funcs plane_helper= _funcs =3D { .atomic_update =3D tilcdc_plane_atomic_update, }; =20 -int tilcdc_plane_init(struct drm_device *dev, - struct drm_plane *plane) +struct tilcdc_plane *tilcdc_plane_init(struct drm_device *dev) { struct tilcdc_drm_private *priv =3D ddev_to_tilcdc_priv(dev); - int ret; - - ret =3D drm_universal_plane_init(dev, plane, 1, &tilcdc_plane_funcs, - priv->pixelformats, - priv->num_pixelformats, - NULL, DRM_PLANE_TYPE_PRIMARY, NULL); - if (ret) { - dev_err(dev->dev, "Failed to initialize plane: %d\n", ret); - return ret; - } + struct tilcdc_plane *plane; =20 - drm_plane_helper_add(plane, &plane_helper_funcs); + plane =3D drmm_universal_plane_alloc(dev, struct tilcdc_plane, base, + 1, &tilcdc_plane_funcs, + priv->pixelformats, + priv->num_pixelformats, + NULL, DRM_PLANE_TYPE_PRIMARY, NULL); + if (IS_ERR(plane)) + return plane; =20 - return 0; + drm_plane_helper_add(&plane->base, &plane_helper_funcs); + + return plane; } --=20 2.43.0