[PATCH] drm/meson: switch to a managed drm device

Anastasia Belova posted 1 patch 1 year, 3 months ago
There is a newer version of this series
drivers/gpu/drm/meson/meson_crtc.c         | 10 +--
drivers/gpu/drm/meson/meson_drv.c          | 71 ++++++++++------------
drivers/gpu/drm/meson/meson_drv.h          |  2 +-
drivers/gpu/drm/meson/meson_encoder_cvbs.c |  8 +--
drivers/gpu/drm/meson/meson_overlay.c      |  8 +--
drivers/gpu/drm/meson/meson_plane.c        | 10 +--
6 files changed, 51 insertions(+), 58 deletions(-)
[PATCH] drm/meson: switch to a managed drm device
Posted by Anastasia Belova 1 year, 3 months ago
Switch to a managed drm device to cleanup some error handling
and make future work easier.

Fix dereference of NULL in meson_drv_bind_master by removing
drm_dev_put(drm) before meson_encoder_*_remove where drm
dereferenced.

Co-developed by Linux Verification Center (linuxtesting.org).

Signed-off-by: Anastasia Belova <abelova@astralinux.ru>
---
 drivers/gpu/drm/meson/meson_crtc.c         | 10 +--
 drivers/gpu/drm/meson/meson_drv.c          | 71 ++++++++++------------
 drivers/gpu/drm/meson/meson_drv.h          |  2 +-
 drivers/gpu/drm/meson/meson_encoder_cvbs.c |  8 +--
 drivers/gpu/drm/meson/meson_overlay.c      |  8 +--
 drivers/gpu/drm/meson/meson_plane.c        | 10 +--
 6 files changed, 51 insertions(+), 58 deletions(-)

diff --git a/drivers/gpu/drm/meson/meson_crtc.c b/drivers/gpu/drm/meson/meson_crtc.c
index d70616da8ce2..e1c0bf3baeea 100644
--- a/drivers/gpu/drm/meson/meson_crtc.c
+++ b/drivers/gpu/drm/meson/meson_crtc.c
@@ -662,13 +662,13 @@ void meson_crtc_irq(struct meson_drm *priv)
 
 	drm_crtc_handle_vblank(priv->crtc);
 
-	spin_lock_irqsave(&priv->drm->event_lock, flags);
+	spin_lock_irqsave(&priv->drm.event_lock, flags);
 	if (meson_crtc->event) {
 		drm_crtc_send_vblank_event(priv->crtc, meson_crtc->event);
 		drm_crtc_vblank_put(priv->crtc);
 		meson_crtc->event = NULL;
 	}
-	spin_unlock_irqrestore(&priv->drm->event_lock, flags);
+	spin_unlock_irqrestore(&priv->drm.event_lock, flags);
 }
 
 int meson_crtc_create(struct meson_drm *priv)
@@ -677,18 +677,18 @@ int meson_crtc_create(struct meson_drm *priv)
 	struct drm_crtc *crtc;
 	int ret;
 
-	meson_crtc = devm_kzalloc(priv->drm->dev, sizeof(*meson_crtc),
+	meson_crtc = devm_kzalloc(priv->drm.dev, sizeof(*meson_crtc),
 				  GFP_KERNEL);
 	if (!meson_crtc)
 		return -ENOMEM;
 
 	meson_crtc->priv = priv;
 	crtc = &meson_crtc->base;
-	ret = drm_crtc_init_with_planes(priv->drm, crtc,
+	ret = drm_crtc_init_with_planes(&priv->drm, crtc,
 					priv->primary_plane, NULL,
 					&meson_crtc_funcs, "meson_crtc");
 	if (ret) {
-		dev_err(priv->drm->dev, "Failed to init CRTC\n");
+		dev_err(priv->drm.dev, "Failed to init CRTC\n");
 		return ret;
 	}
 
diff --git a/drivers/gpu/drm/meson/meson_drv.c b/drivers/gpu/drm/meson/meson_drv.c
index 4bd0baa2a4f5..2e7c2e7c7b82 100644
--- a/drivers/gpu/drm/meson/meson_drv.c
+++ b/drivers/gpu/drm/meson/meson_drv.c
@@ -182,7 +182,6 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
 	struct platform_device *pdev = to_platform_device(dev);
 	const struct meson_drm_match_data *match;
 	struct meson_drm *priv;
-	struct drm_device *drm;
 	struct resource *res;
 	void __iomem *regs;
 	int ret, i;
@@ -197,17 +196,13 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
 	if (!match)
 		return -ENODEV;
 
-	drm = drm_dev_alloc(&meson_driver, dev);
-	if (IS_ERR(drm))
-		return PTR_ERR(drm);
+	priv = devm_drm_dev_alloc(dev, &meson_driver,
+				 struct meson_drm, drm);
 
-	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
-	if (!priv) {
-		ret = -ENOMEM;
-		goto free_drm;
-	}
-	drm->dev_private = priv;
-	priv->drm = drm;
+	if (IS_ERR(priv))
+		return PTR_ERR(priv);
+
+	priv->drm.dev_private = priv;
 	priv->dev = dev;
 	priv->compat = match->compat;
 	priv->afbcd.ops = match->afbcd_ops;
@@ -215,7 +210,7 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
 	regs = devm_platform_ioremap_resource_byname(pdev, "vpu");
 	if (IS_ERR(regs)) {
 		ret = PTR_ERR(regs);
-		goto free_drm;
+		goto remove_encoders;
 	}
 
 	priv->io_base = regs;
@@ -223,13 +218,13 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "hhi");
 	if (!res) {
 		ret = -EINVAL;
-		goto free_drm;
+		goto remove_encoders;
 	}
 	/* Simply ioremap since it may be a shared register zone */
 	regs = devm_ioremap(dev, res->start, resource_size(res));
 	if (!regs) {
 		ret = -EADDRNOTAVAIL;
-		goto free_drm;
+		goto remove_encoders;
 	}
 
 	priv->hhi = devm_regmap_init_mmio(dev, regs,
@@ -237,18 +232,18 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
 	if (IS_ERR(priv->hhi)) {
 		dev_err(&pdev->dev, "Couldn't create the HHI regmap\n");
 		ret = PTR_ERR(priv->hhi);
-		goto free_drm;
+		goto remove_encoders;
 	}
 
 	priv->canvas = meson_canvas_get(dev);
 	if (IS_ERR(priv->canvas)) {
 		ret = PTR_ERR(priv->canvas);
-		goto free_drm;
+		goto remove_encoders;
 	}
 
 	ret = meson_canvas_alloc(priv->canvas, &priv->canvas_id_osd1);
 	if (ret)
-		goto free_drm;
+		goto remove_encoders;
 	ret = meson_canvas_alloc(priv->canvas, &priv->canvas_id_vd1_0);
 	if (ret)
 		goto free_canvas_osd1;
@@ -261,7 +256,7 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
 
 	priv->vsync_irq = platform_get_irq(pdev, 0);
 
-	ret = drm_vblank_init(drm, 1);
+	ret = drm_vblank_init(&priv->drm, 1);
 	if (ret)
 		goto free_canvas_vd1_2;
 
@@ -284,10 +279,10 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
 	ret = drmm_mode_config_init(drm);
 	if (ret)
 		goto free_canvas_vd1_2;
-	drm->mode_config.max_width = 3840;
-	drm->mode_config.max_height = 2160;
-	drm->mode_config.funcs = &meson_mode_config_funcs;
-	drm->mode_config.helper_private	= &meson_mode_config_helpers;
+	priv->drm.mode_config.max_width = 3840;
+	priv->drm.mode_config.max_height = 2160;
+	priv->drm.mode_config.funcs = &meson_mode_config_funcs;
+	priv->drm.mode_config.helper_private = &meson_mode_config_helpers;
 
 	/* Hardware Initialization */
 
@@ -308,9 +303,9 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
 		goto exit_afbcd;
 
 	if (has_components) {
-		ret = component_bind_all(dev, drm);
+		ret = component_bind_all(dev, &priv->drm);
 		if (ret) {
-			dev_err(drm->dev, "Couldn't bind all components\n");
+			dev_err(priv->drm.dev, "Couldn't bind all components\n");
 			/* Do not try to unbind */
 			has_components = false;
 			goto exit_afbcd;
@@ -339,26 +334,26 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
 	if (ret)
 		goto exit_afbcd;
 
-	ret = request_irq(priv->vsync_irq, meson_irq, 0, drm->driver->name, drm);
+	ret = request_irq(priv->vsync_irq, meson_irq, 0, priv->drm.driver->name, &priv->drm);
 	if (ret)
 		goto exit_afbcd;
 
-	drm_mode_config_reset(drm);
+	drm_mode_config_reset(&priv->drm);
 
-	drm_kms_helper_poll_init(drm);
+	drm_kms_helper_poll_init(&priv->drm);
 
 	platform_set_drvdata(pdev, priv);
 
-	ret = drm_dev_register(drm, 0);
+	ret = drm_dev_register(&priv->drm, 0);
 	if (ret)
 		goto uninstall_irq;
 
-	drm_fbdev_dma_setup(drm, 32);
+	drm_fbdev_dma_setup(&priv->drm, 32);
 
 	return 0;
 
 uninstall_irq:
-	free_irq(priv->vsync_irq, drm);
+	free_irq(priv->vsync_irq, &priv->drm);
 exit_afbcd:
 	if (priv->afbcd.ops)
 		priv->afbcd.ops->exit(priv);
@@ -370,15 +365,14 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
 	meson_canvas_free(priv->canvas, priv->canvas_id_vd1_0);
 free_canvas_osd1:
 	meson_canvas_free(priv->canvas, priv->canvas_id_osd1);
-free_drm:
-	drm_dev_put(drm);
+remove_encoders:
 
 	meson_encoder_dsi_remove(priv);
 	meson_encoder_hdmi_remove(priv);
 	meson_encoder_cvbs_remove(priv);
 
 	if (has_components)
-		component_unbind_all(dev, drm);
+		component_unbind_all(dev, &priv->drm);
 
 	return ret;
 }
@@ -391,7 +385,7 @@ static int meson_drv_bind(struct device *dev)
 static void meson_drv_unbind(struct device *dev)
 {
 	struct meson_drm *priv = dev_get_drvdata(dev);
-	struct drm_device *drm = priv->drm;
+	struct drm_device *drm = &priv->drm;
 
 	if (priv->canvas) {
 		meson_canvas_free(priv->canvas, priv->canvas_id_osd1);
@@ -404,7 +398,6 @@ static void meson_drv_unbind(struct device *dev)
 	drm_kms_helper_poll_fini(drm);
 	drm_atomic_helper_shutdown(drm);
 	free_irq(priv->vsync_irq, drm);
-	drm_dev_put(drm);
 
 	meson_encoder_dsi_remove(priv);
 	meson_encoder_hdmi_remove(priv);
@@ -428,7 +421,7 @@ static int __maybe_unused meson_drv_pm_suspend(struct device *dev)
 	if (!priv)
 		return 0;
 
-	return drm_mode_config_helper_suspend(priv->drm);
+	return drm_mode_config_helper_suspend(&priv->drm);
 }
 
 static int __maybe_unused meson_drv_pm_resume(struct device *dev)
@@ -445,7 +438,7 @@ static int __maybe_unused meson_drv_pm_resume(struct device *dev)
 	if (priv->afbcd.ops)
 		priv->afbcd.ops->init(priv);
 
-	return drm_mode_config_helper_resume(priv->drm);
+	return drm_mode_config_helper_resume(&priv->drm);
 }
 
 static void meson_drv_shutdown(struct platform_device *pdev)
@@ -455,8 +448,8 @@ static void meson_drv_shutdown(struct platform_device *pdev)
 	if (!priv)
 		return;
 
-	drm_kms_helper_poll_fini(priv->drm);
-	drm_atomic_helper_shutdown(priv->drm);
+	drm_kms_helper_poll_fini(&priv->drm);
+	drm_atomic_helper_shutdown(&priv->drm);
 }
 
 /*
diff --git a/drivers/gpu/drm/meson/meson_drv.h b/drivers/gpu/drm/meson/meson_drv.h
index 3f9345c14f31..c4c6c810cb20 100644
--- a/drivers/gpu/drm/meson/meson_drv.h
+++ b/drivers/gpu/drm/meson/meson_drv.h
@@ -53,7 +53,7 @@ struct meson_drm {
 	u8 canvas_id_vd1_1;
 	u8 canvas_id_vd1_2;
 
-	struct drm_device *drm;
+	struct drm_device drm;
 	struct drm_crtc *crtc;
 	struct drm_plane *primary_plane;
 	struct drm_plane *overlay_plane;
diff --git a/drivers/gpu/drm/meson/meson_encoder_cvbs.c b/drivers/gpu/drm/meson/meson_encoder_cvbs.c
index d1191de855d9..ddca22c8c1ff 100644
--- a/drivers/gpu/drm/meson/meson_encoder_cvbs.c
+++ b/drivers/gpu/drm/meson/meson_encoder_cvbs.c
@@ -104,7 +104,7 @@ static int meson_encoder_cvbs_get_modes(struct drm_bridge *bridge,
 	for (i = 0; i < MESON_CVBS_MODES_COUNT; ++i) {
 		struct meson_cvbs_mode *meson_mode = &meson_cvbs_modes[i];
 
-		mode = drm_mode_duplicate(priv->drm, &meson_mode->mode);
+		mode = drm_mode_duplicate(&priv->drm, &meson_mode->mode);
 		if (!mode) {
 			dev_err(priv->dev, "Failed to create a new display mode\n");
 			return 0;
@@ -221,7 +221,7 @@ static const struct drm_bridge_funcs meson_encoder_cvbs_bridge_funcs = {
 
 int meson_encoder_cvbs_probe(struct meson_drm *priv)
 {
-	struct drm_device *drm = priv->drm;
+	struct drm_device *drm = &priv->drm;
 	struct meson_encoder_cvbs *meson_encoder_cvbs;
 	struct drm_connector *connector;
 	struct device_node *remote;
@@ -256,7 +256,7 @@ int meson_encoder_cvbs_probe(struct meson_drm *priv)
 	meson_encoder_cvbs->priv = priv;
 
 	/* Encoder */
-	ret = drm_simple_encoder_init(priv->drm, &meson_encoder_cvbs->encoder,
+	ret = drm_simple_encoder_init(&priv->drm, &meson_encoder_cvbs->encoder,
 				      DRM_MODE_ENCODER_TVDAC);
 	if (ret)
 		return dev_err_probe(priv->dev, ret,
@@ -273,7 +273,7 @@ int meson_encoder_cvbs_probe(struct meson_drm *priv)
 	}
 
 	/* Initialize & attach Bridge Connector */
-	connector = drm_bridge_connector_init(priv->drm, &meson_encoder_cvbs->encoder);
+	connector = drm_bridge_connector_init(&priv->drm, &meson_encoder_cvbs->encoder);
 	if (IS_ERR(connector))
 		return dev_err_probe(priv->dev, PTR_ERR(connector),
 				     "Unable to create CVBS bridge connector\n");
diff --git a/drivers/gpu/drm/meson/meson_overlay.c b/drivers/gpu/drm/meson/meson_overlay.c
index 7f98de38842b..60ee7f758723 100644
--- a/drivers/gpu/drm/meson/meson_overlay.c
+++ b/drivers/gpu/drm/meson/meson_overlay.c
@@ -484,7 +484,7 @@ static void meson_overlay_atomic_update(struct drm_plane *plane,
 
 	interlace_mode = new_state->crtc->mode.flags & DRM_MODE_FLAG_INTERLACE;
 
-	spin_lock_irqsave(&priv->drm->event_lock, flags);
+	spin_lock_irqsave(&priv->drm.event_lock, flags);
 
 	if ((fb->modifier & DRM_FORMAT_MOD_AMLOGIC_FBC(0, 0)) ==
 			    DRM_FORMAT_MOD_AMLOGIC_FBC(0, 0)) {
@@ -717,7 +717,7 @@ static void meson_overlay_atomic_update(struct drm_plane *plane,
 
 	priv->viu.vd1_enabled = true;
 
-	spin_unlock_irqrestore(&priv->drm->event_lock, flags);
+	spin_unlock_irqrestore(&priv->drm.event_lock, flags);
 
 	DRM_DEBUG_DRIVER("\n");
 }
@@ -838,7 +838,7 @@ int meson_overlay_create(struct meson_drm *priv)
 
 	DRM_DEBUG_DRIVER("\n");
 
-	meson_overlay = devm_kzalloc(priv->drm->dev, sizeof(*meson_overlay),
+	meson_overlay = devm_kzalloc(priv->drm.dev, sizeof(*meson_overlay),
 				   GFP_KERNEL);
 	if (!meson_overlay)
 		return -ENOMEM;
@@ -846,7 +846,7 @@ int meson_overlay_create(struct meson_drm *priv)
 	meson_overlay->priv = priv;
 	plane = &meson_overlay->base;
 
-	drm_universal_plane_init(priv->drm, plane, 0xFF,
+	drm_universal_plane_init(&priv->drm, plane, 0xFF,
 				 &meson_overlay_funcs,
 				 supported_drm_formats,
 				 ARRAY_SIZE(supported_drm_formats),
diff --git a/drivers/gpu/drm/meson/meson_plane.c b/drivers/gpu/drm/meson/meson_plane.c
index b43ac61201f3..13be94309bf4 100644
--- a/drivers/gpu/drm/meson/meson_plane.c
+++ b/drivers/gpu/drm/meson/meson_plane.c
@@ -157,7 +157,7 @@ static void meson_plane_atomic_update(struct drm_plane *plane,
 	 * Update Buffer
 	 * Enable Plane
 	 */
-	spin_lock_irqsave(&priv->drm->event_lock, flags);
+	spin_lock_irqsave(&priv->drm.event_lock, flags);
 
 	/* Check if AFBC decoder is required for this buffer */
 	if ((meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM) ||
@@ -393,7 +393,7 @@ static void meson_plane_atomic_update(struct drm_plane *plane,
 
 	priv->viu.osd1_enabled = true;
 
-	spin_unlock_irqrestore(&priv->drm->event_lock, flags);
+	spin_unlock_irqrestore(&priv->drm.event_lock, flags);
 }
 
 static void meson_plane_atomic_disable(struct drm_plane *plane,
@@ -536,7 +536,7 @@ int meson_plane_create(struct meson_drm *priv)
 	const uint64_t *format_modifiers = format_modifiers_default;
 	int ret;
 
-	meson_plane = devm_kzalloc(priv->drm->dev, sizeof(*meson_plane),
+	meson_plane = devm_kzalloc(priv->drm.dev, sizeof(*meson_plane),
 				   GFP_KERNEL);
 	if (!meson_plane)
 		return -ENOMEM;
@@ -549,14 +549,14 @@ int meson_plane_create(struct meson_drm *priv)
 	else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A))
 		format_modifiers = format_modifiers_afbc_g12a;
 
-	ret = drm_universal_plane_init(priv->drm, plane, 0xFF,
+	ret = drm_universal_plane_init(&priv->drm, plane, 0xFF,
 					&meson_plane_funcs,
 					supported_drm_formats,
 					ARRAY_SIZE(supported_drm_formats),
 					format_modifiers,
 					DRM_PLANE_TYPE_PRIMARY, "meson_primary_plane");
 	if (ret) {
-		devm_kfree(priv->drm->dev, meson_plane);
+		devm_kfree(priv->drm.dev, meson_plane);
 		return ret;
 	}
 
-- 
2.30.2
Re: [PATCH] drm/meson: switch to a managed drm device
Posted by Neil Armstrong 1 year, 3 months ago
Hi,

On 28/08/2024 13:04, Anastasia Belova wrote:
> Switch to a managed drm device to cleanup some error handling
> and make future work easier.
> 
> Fix dereference of NULL in meson_drv_bind_master by removing
> drm_dev_put(drm) before meson_encoder_*_remove where drm
> dereferenced.

Please send the fix separately with a Fixes tag.

Thanks,
Neil

> 
> Co-developed by Linux Verification Center (linuxtesting.org).
> 
> Signed-off-by: Anastasia Belova <abelova@astralinux.ru>
> ---
>   drivers/gpu/drm/meson/meson_crtc.c         | 10 +--
>   drivers/gpu/drm/meson/meson_drv.c          | 71 ++++++++++------------
>   drivers/gpu/drm/meson/meson_drv.h          |  2 +-
>   drivers/gpu/drm/meson/meson_encoder_cvbs.c |  8 +--
>   drivers/gpu/drm/meson/meson_overlay.c      |  8 +--
>   drivers/gpu/drm/meson/meson_plane.c        | 10 +--
>   6 files changed, 51 insertions(+), 58 deletions(-)
> 
> diff --git a/drivers/gpu/drm/meson/meson_crtc.c b/drivers/gpu/drm/meson/meson_crtc.c
> index d70616da8ce2..e1c0bf3baeea 100644
> --- a/drivers/gpu/drm/meson/meson_crtc.c
> +++ b/drivers/gpu/drm/meson/meson_crtc.c
> @@ -662,13 +662,13 @@ void meson_crtc_irq(struct meson_drm *priv)
>   
>   	drm_crtc_handle_vblank(priv->crtc);
>   
> -	spin_lock_irqsave(&priv->drm->event_lock, flags);
> +	spin_lock_irqsave(&priv->drm.event_lock, flags);
>   	if (meson_crtc->event) {
>   		drm_crtc_send_vblank_event(priv->crtc, meson_crtc->event);
>   		drm_crtc_vblank_put(priv->crtc);
>   		meson_crtc->event = NULL;
>   	}
> -	spin_unlock_irqrestore(&priv->drm->event_lock, flags);
> +	spin_unlock_irqrestore(&priv->drm.event_lock, flags);
>   }
>   
>   int meson_crtc_create(struct meson_drm *priv)
> @@ -677,18 +677,18 @@ int meson_crtc_create(struct meson_drm *priv)
>   	struct drm_crtc *crtc;
>   	int ret;
>   
> -	meson_crtc = devm_kzalloc(priv->drm->dev, sizeof(*meson_crtc),
> +	meson_crtc = devm_kzalloc(priv->drm.dev, sizeof(*meson_crtc),
>   				  GFP_KERNEL);
>   	if (!meson_crtc)
>   		return -ENOMEM;
>   
>   	meson_crtc->priv = priv;
>   	crtc = &meson_crtc->base;
> -	ret = drm_crtc_init_with_planes(priv->drm, crtc,
> +	ret = drm_crtc_init_with_planes(&priv->drm, crtc,
>   					priv->primary_plane, NULL,
>   					&meson_crtc_funcs, "meson_crtc");
>   	if (ret) {
> -		dev_err(priv->drm->dev, "Failed to init CRTC\n");
> +		dev_err(priv->drm.dev, "Failed to init CRTC\n");
>   		return ret;
>   	}
>   
> diff --git a/drivers/gpu/drm/meson/meson_drv.c b/drivers/gpu/drm/meson/meson_drv.c
> index 4bd0baa2a4f5..2e7c2e7c7b82 100644
> --- a/drivers/gpu/drm/meson/meson_drv.c
> +++ b/drivers/gpu/drm/meson/meson_drv.c
> @@ -182,7 +182,6 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
>   	struct platform_device *pdev = to_platform_device(dev);
>   	const struct meson_drm_match_data *match;
>   	struct meson_drm *priv;
> -	struct drm_device *drm;
>   	struct resource *res;
>   	void __iomem *regs;
>   	int ret, i;
> @@ -197,17 +196,13 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
>   	if (!match)
>   		return -ENODEV;
>   
> -	drm = drm_dev_alloc(&meson_driver, dev);
> -	if (IS_ERR(drm))
> -		return PTR_ERR(drm);
> +	priv = devm_drm_dev_alloc(dev, &meson_driver,
> +				 struct meson_drm, drm);
>   
> -	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> -	if (!priv) {
> -		ret = -ENOMEM;
> -		goto free_drm;
> -	}
> -	drm->dev_private = priv;
> -	priv->drm = drm;
> +	if (IS_ERR(priv))
> +		return PTR_ERR(priv);
> +
> +	priv->drm.dev_private = priv;
>   	priv->dev = dev;
>   	priv->compat = match->compat;
>   	priv->afbcd.ops = match->afbcd_ops;
> @@ -215,7 +210,7 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
>   	regs = devm_platform_ioremap_resource_byname(pdev, "vpu");
>   	if (IS_ERR(regs)) {
>   		ret = PTR_ERR(regs);
> -		goto free_drm;
> +		goto remove_encoders;
>   	}
>   
>   	priv->io_base = regs;
> @@ -223,13 +218,13 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
>   	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "hhi");
>   	if (!res) {
>   		ret = -EINVAL;
> -		goto free_drm;
> +		goto remove_encoders;
>   	}
>   	/* Simply ioremap since it may be a shared register zone */
>   	regs = devm_ioremap(dev, res->start, resource_size(res));
>   	if (!regs) {
>   		ret = -EADDRNOTAVAIL;
> -		goto free_drm;
> +		goto remove_encoders;
>   	}
>   
>   	priv->hhi = devm_regmap_init_mmio(dev, regs,
> @@ -237,18 +232,18 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
>   	if (IS_ERR(priv->hhi)) {
>   		dev_err(&pdev->dev, "Couldn't create the HHI regmap\n");
>   		ret = PTR_ERR(priv->hhi);
> -		goto free_drm;
> +		goto remove_encoders;
>   	}
>   
>   	priv->canvas = meson_canvas_get(dev);
>   	if (IS_ERR(priv->canvas)) {
>   		ret = PTR_ERR(priv->canvas);
> -		goto free_drm;
> +		goto remove_encoders;
>   	}
>   
>   	ret = meson_canvas_alloc(priv->canvas, &priv->canvas_id_osd1);
>   	if (ret)
> -		goto free_drm;
> +		goto remove_encoders;
>   	ret = meson_canvas_alloc(priv->canvas, &priv->canvas_id_vd1_0);
>   	if (ret)
>   		goto free_canvas_osd1;
> @@ -261,7 +256,7 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
>   
>   	priv->vsync_irq = platform_get_irq(pdev, 0);
>   
> -	ret = drm_vblank_init(drm, 1);
> +	ret = drm_vblank_init(&priv->drm, 1);
>   	if (ret)
>   		goto free_canvas_vd1_2;
>   
> @@ -284,10 +279,10 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
>   	ret = drmm_mode_config_init(drm);
>   	if (ret)
>   		goto free_canvas_vd1_2;
> -	drm->mode_config.max_width = 3840;
> -	drm->mode_config.max_height = 2160;
> -	drm->mode_config.funcs = &meson_mode_config_funcs;
> -	drm->mode_config.helper_private	= &meson_mode_config_helpers;
> +	priv->drm.mode_config.max_width = 3840;
> +	priv->drm.mode_config.max_height = 2160;
> +	priv->drm.mode_config.funcs = &meson_mode_config_funcs;
> +	priv->drm.mode_config.helper_private = &meson_mode_config_helpers;
>   
>   	/* Hardware Initialization */
>   
> @@ -308,9 +303,9 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
>   		goto exit_afbcd;
>   
>   	if (has_components) {
> -		ret = component_bind_all(dev, drm);
> +		ret = component_bind_all(dev, &priv->drm);
>   		if (ret) {
> -			dev_err(drm->dev, "Couldn't bind all components\n");
> +			dev_err(priv->drm.dev, "Couldn't bind all components\n");
>   			/* Do not try to unbind */
>   			has_components = false;
>   			goto exit_afbcd;
> @@ -339,26 +334,26 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
>   	if (ret)
>   		goto exit_afbcd;
>   
> -	ret = request_irq(priv->vsync_irq, meson_irq, 0, drm->driver->name, drm);
> +	ret = request_irq(priv->vsync_irq, meson_irq, 0, priv->drm.driver->name, &priv->drm);
>   	if (ret)
>   		goto exit_afbcd;
>   
> -	drm_mode_config_reset(drm);
> +	drm_mode_config_reset(&priv->drm);
>   
> -	drm_kms_helper_poll_init(drm);
> +	drm_kms_helper_poll_init(&priv->drm);
>   
>   	platform_set_drvdata(pdev, priv);
>   
> -	ret = drm_dev_register(drm, 0);
> +	ret = drm_dev_register(&priv->drm, 0);
>   	if (ret)
>   		goto uninstall_irq;
>   
> -	drm_fbdev_dma_setup(drm, 32);
> +	drm_fbdev_dma_setup(&priv->drm, 32);
>   
>   	return 0;
>   
>   uninstall_irq:
> -	free_irq(priv->vsync_irq, drm);
> +	free_irq(priv->vsync_irq, &priv->drm);
>   exit_afbcd:
>   	if (priv->afbcd.ops)
>   		priv->afbcd.ops->exit(priv);
> @@ -370,15 +365,14 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
>   	meson_canvas_free(priv->canvas, priv->canvas_id_vd1_0);
>   free_canvas_osd1:
>   	meson_canvas_free(priv->canvas, priv->canvas_id_osd1);
> -free_drm:
> -	drm_dev_put(drm);
> +remove_encoders:
>   
>   	meson_encoder_dsi_remove(priv);
>   	meson_encoder_hdmi_remove(priv);
>   	meson_encoder_cvbs_remove(priv);
>   
>   	if (has_components)
> -		component_unbind_all(dev, drm);
> +		component_unbind_all(dev, &priv->drm);
>   
>   	return ret;
>   }
> @@ -391,7 +385,7 @@ static int meson_drv_bind(struct device *dev)
>   static void meson_drv_unbind(struct device *dev)
>   {
>   	struct meson_drm *priv = dev_get_drvdata(dev);
> -	struct drm_device *drm = priv->drm;
> +	struct drm_device *drm = &priv->drm;
>   
>   	if (priv->canvas) {
>   		meson_canvas_free(priv->canvas, priv->canvas_id_osd1);
> @@ -404,7 +398,6 @@ static void meson_drv_unbind(struct device *dev)
>   	drm_kms_helper_poll_fini(drm);
>   	drm_atomic_helper_shutdown(drm);
>   	free_irq(priv->vsync_irq, drm);
> -	drm_dev_put(drm);
>   
>   	meson_encoder_dsi_remove(priv);
>   	meson_encoder_hdmi_remove(priv);
> @@ -428,7 +421,7 @@ static int __maybe_unused meson_drv_pm_suspend(struct device *dev)
>   	if (!priv)
>   		return 0;
>   
> -	return drm_mode_config_helper_suspend(priv->drm);
> +	return drm_mode_config_helper_suspend(&priv->drm);
>   }
>   
>   static int __maybe_unused meson_drv_pm_resume(struct device *dev)
> @@ -445,7 +438,7 @@ static int __maybe_unused meson_drv_pm_resume(struct device *dev)
>   	if (priv->afbcd.ops)
>   		priv->afbcd.ops->init(priv);
>   
> -	return drm_mode_config_helper_resume(priv->drm);
> +	return drm_mode_config_helper_resume(&priv->drm);
>   }
>   
>   static void meson_drv_shutdown(struct platform_device *pdev)
> @@ -455,8 +448,8 @@ static void meson_drv_shutdown(struct platform_device *pdev)
>   	if (!priv)
>   		return;
>   
> -	drm_kms_helper_poll_fini(priv->drm);
> -	drm_atomic_helper_shutdown(priv->drm);
> +	drm_kms_helper_poll_fini(&priv->drm);
> +	drm_atomic_helper_shutdown(&priv->drm);
>   }
>   
>   /*
> diff --git a/drivers/gpu/drm/meson/meson_drv.h b/drivers/gpu/drm/meson/meson_drv.h
> index 3f9345c14f31..c4c6c810cb20 100644
> --- a/drivers/gpu/drm/meson/meson_drv.h
> +++ b/drivers/gpu/drm/meson/meson_drv.h
> @@ -53,7 +53,7 @@ struct meson_drm {
>   	u8 canvas_id_vd1_1;
>   	u8 canvas_id_vd1_2;
>   
> -	struct drm_device *drm;
> +	struct drm_device drm;
>   	struct drm_crtc *crtc;
>   	struct drm_plane *primary_plane;
>   	struct drm_plane *overlay_plane;
> diff --git a/drivers/gpu/drm/meson/meson_encoder_cvbs.c b/drivers/gpu/drm/meson/meson_encoder_cvbs.c
> index d1191de855d9..ddca22c8c1ff 100644
> --- a/drivers/gpu/drm/meson/meson_encoder_cvbs.c
> +++ b/drivers/gpu/drm/meson/meson_encoder_cvbs.c
> @@ -104,7 +104,7 @@ static int meson_encoder_cvbs_get_modes(struct drm_bridge *bridge,
>   	for (i = 0; i < MESON_CVBS_MODES_COUNT; ++i) {
>   		struct meson_cvbs_mode *meson_mode = &meson_cvbs_modes[i];
>   
> -		mode = drm_mode_duplicate(priv->drm, &meson_mode->mode);
> +		mode = drm_mode_duplicate(&priv->drm, &meson_mode->mode);
>   		if (!mode) {
>   			dev_err(priv->dev, "Failed to create a new display mode\n");
>   			return 0;
> @@ -221,7 +221,7 @@ static const struct drm_bridge_funcs meson_encoder_cvbs_bridge_funcs = {
>   
>   int meson_encoder_cvbs_probe(struct meson_drm *priv)
>   {
> -	struct drm_device *drm = priv->drm;
> +	struct drm_device *drm = &priv->drm;
>   	struct meson_encoder_cvbs *meson_encoder_cvbs;
>   	struct drm_connector *connector;
>   	struct device_node *remote;
> @@ -256,7 +256,7 @@ int meson_encoder_cvbs_probe(struct meson_drm *priv)
>   	meson_encoder_cvbs->priv = priv;
>   
>   	/* Encoder */
> -	ret = drm_simple_encoder_init(priv->drm, &meson_encoder_cvbs->encoder,
> +	ret = drm_simple_encoder_init(&priv->drm, &meson_encoder_cvbs->encoder,
>   				      DRM_MODE_ENCODER_TVDAC);
>   	if (ret)
>   		return dev_err_probe(priv->dev, ret,
> @@ -273,7 +273,7 @@ int meson_encoder_cvbs_probe(struct meson_drm *priv)
>   	}
>   
>   	/* Initialize & attach Bridge Connector */
> -	connector = drm_bridge_connector_init(priv->drm, &meson_encoder_cvbs->encoder);
> +	connector = drm_bridge_connector_init(&priv->drm, &meson_encoder_cvbs->encoder);
>   	if (IS_ERR(connector))
>   		return dev_err_probe(priv->dev, PTR_ERR(connector),
>   				     "Unable to create CVBS bridge connector\n");
> diff --git a/drivers/gpu/drm/meson/meson_overlay.c b/drivers/gpu/drm/meson/meson_overlay.c
> index 7f98de38842b..60ee7f758723 100644
> --- a/drivers/gpu/drm/meson/meson_overlay.c
> +++ b/drivers/gpu/drm/meson/meson_overlay.c
> @@ -484,7 +484,7 @@ static void meson_overlay_atomic_update(struct drm_plane *plane,
>   
>   	interlace_mode = new_state->crtc->mode.flags & DRM_MODE_FLAG_INTERLACE;
>   
> -	spin_lock_irqsave(&priv->drm->event_lock, flags);
> +	spin_lock_irqsave(&priv->drm.event_lock, flags);
>   
>   	if ((fb->modifier & DRM_FORMAT_MOD_AMLOGIC_FBC(0, 0)) ==
>   			    DRM_FORMAT_MOD_AMLOGIC_FBC(0, 0)) {
> @@ -717,7 +717,7 @@ static void meson_overlay_atomic_update(struct drm_plane *plane,
>   
>   	priv->viu.vd1_enabled = true;
>   
> -	spin_unlock_irqrestore(&priv->drm->event_lock, flags);
> +	spin_unlock_irqrestore(&priv->drm.event_lock, flags);
>   
>   	DRM_DEBUG_DRIVER("\n");
>   }
> @@ -838,7 +838,7 @@ int meson_overlay_create(struct meson_drm *priv)
>   
>   	DRM_DEBUG_DRIVER("\n");
>   
> -	meson_overlay = devm_kzalloc(priv->drm->dev, sizeof(*meson_overlay),
> +	meson_overlay = devm_kzalloc(priv->drm.dev, sizeof(*meson_overlay),
>   				   GFP_KERNEL);
>   	if (!meson_overlay)
>   		return -ENOMEM;
> @@ -846,7 +846,7 @@ int meson_overlay_create(struct meson_drm *priv)
>   	meson_overlay->priv = priv;
>   	plane = &meson_overlay->base;
>   
> -	drm_universal_plane_init(priv->drm, plane, 0xFF,
> +	drm_universal_plane_init(&priv->drm, plane, 0xFF,
>   				 &meson_overlay_funcs,
>   				 supported_drm_formats,
>   				 ARRAY_SIZE(supported_drm_formats),
> diff --git a/drivers/gpu/drm/meson/meson_plane.c b/drivers/gpu/drm/meson/meson_plane.c
> index b43ac61201f3..13be94309bf4 100644
> --- a/drivers/gpu/drm/meson/meson_plane.c
> +++ b/drivers/gpu/drm/meson/meson_plane.c
> @@ -157,7 +157,7 @@ static void meson_plane_atomic_update(struct drm_plane *plane,
>   	 * Update Buffer
>   	 * Enable Plane
>   	 */
> -	spin_lock_irqsave(&priv->drm->event_lock, flags);
> +	spin_lock_irqsave(&priv->drm.event_lock, flags);
>   
>   	/* Check if AFBC decoder is required for this buffer */
>   	if ((meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM) ||
> @@ -393,7 +393,7 @@ static void meson_plane_atomic_update(struct drm_plane *plane,
>   
>   	priv->viu.osd1_enabled = true;
>   
> -	spin_unlock_irqrestore(&priv->drm->event_lock, flags);
> +	spin_unlock_irqrestore(&priv->drm.event_lock, flags);
>   }
>   
>   static void meson_plane_atomic_disable(struct drm_plane *plane,
> @@ -536,7 +536,7 @@ int meson_plane_create(struct meson_drm *priv)
>   	const uint64_t *format_modifiers = format_modifiers_default;
>   	int ret;
>   
> -	meson_plane = devm_kzalloc(priv->drm->dev, sizeof(*meson_plane),
> +	meson_plane = devm_kzalloc(priv->drm.dev, sizeof(*meson_plane),
>   				   GFP_KERNEL);
>   	if (!meson_plane)
>   		return -ENOMEM;
> @@ -549,14 +549,14 @@ int meson_plane_create(struct meson_drm *priv)
>   	else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A))
>   		format_modifiers = format_modifiers_afbc_g12a;
>   
> -	ret = drm_universal_plane_init(priv->drm, plane, 0xFF,
> +	ret = drm_universal_plane_init(&priv->drm, plane, 0xFF,
>   					&meson_plane_funcs,
>   					supported_drm_formats,
>   					ARRAY_SIZE(supported_drm_formats),
>   					format_modifiers,
>   					DRM_PLANE_TYPE_PRIMARY, "meson_primary_plane");
>   	if (ret) {
> -		devm_kfree(priv->drm->dev, meson_plane);
> +		devm_kfree(priv->drm.dev, meson_plane);
>   		return ret;
>   	}
>
Re: [PATCH] drm/meson: switch to a managed drm device
Posted by Anastasia Belova 1 year, 3 months ago
Hi,

29/08/24 15:14, Neil Armstrong пишет:
> Hi,
>
> On 28/08/2024 13:04, Anastasia Belova wrote:
>> Switch to a managed drm device to cleanup some error handling
>> and make future work easier.
>>
>> Fix dereference of NULL in meson_drv_bind_master by removing
>> drm_dev_put(drm) before meson_encoder_*_remove where drm
>> dereferenced.
>
> Please send the fix separately with a Fixes tag.
>

This fix can't be separated from the patch. drm_dev_put may be
removed only while switching to a managed drm. Otherwise
a check could be added before calling meson_encoder_*_remove.
But it would become redundant after switching to a managed drm.

I may send the second version of this patch with Fixes tag, so all
changes could be applied to older versions.

Thanks,
Anastasia Belova

> Thanks,
> Neil
>
>>
>> Co-developed by Linux Verification Center (linuxtesting.org).
>>
>> Signed-off-by: Anastasia Belova <abelova@astralinux.ru>
>> ---
>>   drivers/gpu/drm/meson/meson_crtc.c         | 10 +--
>>   drivers/gpu/drm/meson/meson_drv.c          | 71 ++++++++++------------
>>   drivers/gpu/drm/meson/meson_drv.h          |  2 +-
>>   drivers/gpu/drm/meson/meson_encoder_cvbs.c |  8 +--
>>   drivers/gpu/drm/meson/meson_overlay.c      |  8 +--
>>   drivers/gpu/drm/meson/meson_plane.c        | 10 +--
>>   6 files changed, 51 insertions(+), 58 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/meson/meson_crtc.c 
>> b/drivers/gpu/drm/meson/meson_crtc.c
>> index d70616da8ce2..e1c0bf3baeea 100644
>> --- a/drivers/gpu/drm/meson/meson_crtc.c
>> +++ b/drivers/gpu/drm/meson/meson_crtc.c
>> @@ -662,13 +662,13 @@ void meson_crtc_irq(struct meson_drm *priv)
>>         drm_crtc_handle_vblank(priv->crtc);
>>   -    spin_lock_irqsave(&priv->drm->event_lock, flags);
>> +    spin_lock_irqsave(&priv->drm.event_lock, flags);
>>       if (meson_crtc->event) {
>>           drm_crtc_send_vblank_event(priv->crtc, meson_crtc->event);
>>           drm_crtc_vblank_put(priv->crtc);
>>           meson_crtc->event = NULL;
>>       }
>> -    spin_unlock_irqrestore(&priv->drm->event_lock, flags);
>> +    spin_unlock_irqrestore(&priv->drm.event_lock, flags);
>>   }
>>     int meson_crtc_create(struct meson_drm *priv)
>> @@ -677,18 +677,18 @@ int meson_crtc_create(struct meson_drm *priv)
>>       struct drm_crtc *crtc;
>>       int ret;
>>   -    meson_crtc = devm_kzalloc(priv->drm->dev, sizeof(*meson_crtc),
>> +    meson_crtc = devm_kzalloc(priv->drm.dev, sizeof(*meson_crtc),
>>                     GFP_KERNEL);
>>       if (!meson_crtc)
>>           return -ENOMEM;
>>         meson_crtc->priv = priv;
>>       crtc = &meson_crtc->base;
>> -    ret = drm_crtc_init_with_planes(priv->drm, crtc,
>> +    ret = drm_crtc_init_with_planes(&priv->drm, crtc,
>>                       priv->primary_plane, NULL,
>>                       &meson_crtc_funcs, "meson_crtc");
>>       if (ret) {
>> -        dev_err(priv->drm->dev, "Failed to init CRTC\n");
>> +        dev_err(priv->drm.dev, "Failed to init CRTC\n");
>>           return ret;
>>       }
>>   diff --git a/drivers/gpu/drm/meson/meson_drv.c 
>> b/drivers/gpu/drm/meson/meson_drv.c
>> index 4bd0baa2a4f5..2e7c2e7c7b82 100644
>> --- a/drivers/gpu/drm/meson/meson_drv.c
>> +++ b/drivers/gpu/drm/meson/meson_drv.c
>> @@ -182,7 +182,6 @@ static int meson_drv_bind_master(struct device 
>> *dev, bool has_components)
>>       struct platform_device *pdev = to_platform_device(dev);
>>       const struct meson_drm_match_data *match;
>>       struct meson_drm *priv;
>> -    struct drm_device *drm;
>>       struct resource *res;
>>       void __iomem *regs;
>>       int ret, i;
>> @@ -197,17 +196,13 @@ static int meson_drv_bind_master(struct device 
>> *dev, bool has_components)
>>       if (!match)
>>           return -ENODEV;
>>   -    drm = drm_dev_alloc(&meson_driver, dev);
>> -    if (IS_ERR(drm))
>> -        return PTR_ERR(drm);
>> +    priv = devm_drm_dev_alloc(dev, &meson_driver,
>> +                 struct meson_drm, drm);
>>   -    priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
>> -    if (!priv) {
>> -        ret = -ENOMEM;
>> -        goto free_drm;
>> -    }
>> -    drm->dev_private = priv;
>> -    priv->drm = drm;
>> +    if (IS_ERR(priv))
>> +        return PTR_ERR(priv);
>> +
>> +    priv->drm.dev_private = priv;
>>       priv->dev = dev;
>>       priv->compat = match->compat;
>>       priv->afbcd.ops = match->afbcd_ops;
>> @@ -215,7 +210,7 @@ static int meson_drv_bind_master(struct device 
>> *dev, bool has_components)
>>       regs = devm_platform_ioremap_resource_byname(pdev, "vpu");
>>       if (IS_ERR(regs)) {
>>           ret = PTR_ERR(regs);
>> -        goto free_drm;
>> +        goto remove_encoders;
>>       }
>>         priv->io_base = regs;
>> @@ -223,13 +218,13 @@ static int meson_drv_bind_master(struct device 
>> *dev, bool has_components)
>>       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "hhi");
>>       if (!res) {
>>           ret = -EINVAL;
>> -        goto free_drm;
>> +        goto remove_encoders;
>>       }
>>       /* Simply ioremap since it may be a shared register zone */
>>       regs = devm_ioremap(dev, res->start, resource_size(res));
>>       if (!regs) {
>>           ret = -EADDRNOTAVAIL;
>> -        goto free_drm;
>> +        goto remove_encoders;
>>       }
>>         priv->hhi = devm_regmap_init_mmio(dev, regs,
>> @@ -237,18 +232,18 @@ static int meson_drv_bind_master(struct device 
>> *dev, bool has_components)
>>       if (IS_ERR(priv->hhi)) {
>>           dev_err(&pdev->dev, "Couldn't create the HHI regmap\n");
>>           ret = PTR_ERR(priv->hhi);
>> -        goto free_drm;
>> +        goto remove_encoders;
>>       }
>>         priv->canvas = meson_canvas_get(dev);
>>       if (IS_ERR(priv->canvas)) {
>>           ret = PTR_ERR(priv->canvas);
>> -        goto free_drm;
>> +        goto remove_encoders;
>>       }
>>         ret = meson_canvas_alloc(priv->canvas, &priv->canvas_id_osd1);
>>       if (ret)
>> -        goto free_drm;
>> +        goto remove_encoders;
>>       ret = meson_canvas_alloc(priv->canvas, &priv->canvas_id_vd1_0);
>>       if (ret)
>>           goto free_canvas_osd1;
>> @@ -261,7 +256,7 @@ static int meson_drv_bind_master(struct device 
>> *dev, bool has_components)
>>         priv->vsync_irq = platform_get_irq(pdev, 0);
>>   -    ret = drm_vblank_init(drm, 1);
>> +    ret = drm_vblank_init(&priv->drm, 1);
>>       if (ret)
>>           goto free_canvas_vd1_2;
>>   @@ -284,10 +279,10 @@ static int meson_drv_bind_master(struct 
>> device *dev, bool has_components)
>>       ret = drmm_mode_config_init(drm);
>>       if (ret)
>>           goto free_canvas_vd1_2;
>> -    drm->mode_config.max_width = 3840;
>> -    drm->mode_config.max_height = 2160;
>> -    drm->mode_config.funcs = &meson_mode_config_funcs;
>> -    drm->mode_config.helper_private    = &meson_mode_config_helpers;
>> +    priv->drm.mode_config.max_width = 3840;
>> +    priv->drm.mode_config.max_height = 2160;
>> +    priv->drm.mode_config.funcs = &meson_mode_config_funcs;
>> +    priv->drm.mode_config.helper_private = &meson_mode_config_helpers;
>>         /* Hardware Initialization */
>>   @@ -308,9 +303,9 @@ static int meson_drv_bind_master(struct device 
>> *dev, bool has_components)
>>           goto exit_afbcd;
>>         if (has_components) {
>> -        ret = component_bind_all(dev, drm);
>> +        ret = component_bind_all(dev, &priv->drm);
>>           if (ret) {
>> -            dev_err(drm->dev, "Couldn't bind all components\n");
>> +            dev_err(priv->drm.dev, "Couldn't bind all components\n");
>>               /* Do not try to unbind */
>>               has_components = false;
>>               goto exit_afbcd;
>> @@ -339,26 +334,26 @@ static int meson_drv_bind_master(struct device 
>> *dev, bool has_components)
>>       if (ret)
>>           goto exit_afbcd;
>>   -    ret = request_irq(priv->vsync_irq, meson_irq, 0, 
>> drm->driver->name, drm);
>> +    ret = request_irq(priv->vsync_irq, meson_irq, 0, 
>> priv->drm.driver->name, &priv->drm);
>>       if (ret)
>>           goto exit_afbcd;
>>   -    drm_mode_config_reset(drm);
>> +    drm_mode_config_reset(&priv->drm);
>>   -    drm_kms_helper_poll_init(drm);
>> +    drm_kms_helper_poll_init(&priv->drm);
>>         platform_set_drvdata(pdev, priv);
>>   -    ret = drm_dev_register(drm, 0);
>> +    ret = drm_dev_register(&priv->drm, 0);
>>       if (ret)
>>           goto uninstall_irq;
>>   -    drm_fbdev_dma_setup(drm, 32);
>> +    drm_fbdev_dma_setup(&priv->drm, 32);
>>         return 0;
>>     uninstall_irq:
>> -    free_irq(priv->vsync_irq, drm);
>> +    free_irq(priv->vsync_irq, &priv->drm);
>>   exit_afbcd:
>>       if (priv->afbcd.ops)
>>           priv->afbcd.ops->exit(priv);
>> @@ -370,15 +365,14 @@ static int meson_drv_bind_master(struct device 
>> *dev, bool has_components)
>>       meson_canvas_free(priv->canvas, priv->canvas_id_vd1_0);
>>   free_canvas_osd1:
>>       meson_canvas_free(priv->canvas, priv->canvas_id_osd1);
>> -free_drm:
>> -    drm_dev_put(drm);
>> +remove_encoders:
>>         meson_encoder_dsi_remove(priv);
>>       meson_encoder_hdmi_remove(priv);
>>       meson_encoder_cvbs_remove(priv);
>>         if (has_components)
>> -        component_unbind_all(dev, drm);
>> +        component_unbind_all(dev, &priv->drm);
>>         return ret;
>>   }
>> @@ -391,7 +385,7 @@ static int meson_drv_bind(struct device *dev)
>>   static void meson_drv_unbind(struct device *dev)
>>   {
>>       struct meson_drm *priv = dev_get_drvdata(dev);
>> -    struct drm_device *drm = priv->drm;
>> +    struct drm_device *drm = &priv->drm;
>>         if (priv->canvas) {
>>           meson_canvas_free(priv->canvas, priv->canvas_id_osd1);
>> @@ -404,7 +398,6 @@ static void meson_drv_unbind(struct device *dev)
>>       drm_kms_helper_poll_fini(drm);
>>       drm_atomic_helper_shutdown(drm);
>>       free_irq(priv->vsync_irq, drm);
>> -    drm_dev_put(drm);
>>         meson_encoder_dsi_remove(priv);
>>       meson_encoder_hdmi_remove(priv);
>> @@ -428,7 +421,7 @@ static int __maybe_unused 
>> meson_drv_pm_suspend(struct device *dev)
>>       if (!priv)
>>           return 0;
>>   -    return drm_mode_config_helper_suspend(priv->drm);
>> +    return drm_mode_config_helper_suspend(&priv->drm);
>>   }
>>     static int __maybe_unused meson_drv_pm_resume(struct device *dev)
>> @@ -445,7 +438,7 @@ static int __maybe_unused 
>> meson_drv_pm_resume(struct device *dev)
>>       if (priv->afbcd.ops)
>>           priv->afbcd.ops->init(priv);
>>   -    return drm_mode_config_helper_resume(priv->drm);
>> +    return drm_mode_config_helper_resume(&priv->drm);
>>   }
>>     static void meson_drv_shutdown(struct platform_device *pdev)
>> @@ -455,8 +448,8 @@ static void meson_drv_shutdown(struct 
>> platform_device *pdev)
>>       if (!priv)
>>           return;
>>   -    drm_kms_helper_poll_fini(priv->drm);
>> -    drm_atomic_helper_shutdown(priv->drm);
>> +    drm_kms_helper_poll_fini(&priv->drm);
>> +    drm_atomic_helper_shutdown(&priv->drm);
>>   }
>>     /*
>> diff --git a/drivers/gpu/drm/meson/meson_drv.h 
>> b/drivers/gpu/drm/meson/meson_drv.h
>> index 3f9345c14f31..c4c6c810cb20 100644
>> --- a/drivers/gpu/drm/meson/meson_drv.h
>> +++ b/drivers/gpu/drm/meson/meson_drv.h
>> @@ -53,7 +53,7 @@ struct meson_drm {
>>       u8 canvas_id_vd1_1;
>>       u8 canvas_id_vd1_2;
>>   -    struct drm_device *drm;
>> +    struct drm_device drm;
>>       struct drm_crtc *crtc;
>>       struct drm_plane *primary_plane;
>>       struct drm_plane *overlay_plane;
>> diff --git a/drivers/gpu/drm/meson/meson_encoder_cvbs.c 
>> b/drivers/gpu/drm/meson/meson_encoder_cvbs.c
>> index d1191de855d9..ddca22c8c1ff 100644
>> --- a/drivers/gpu/drm/meson/meson_encoder_cvbs.c
>> +++ b/drivers/gpu/drm/meson/meson_encoder_cvbs.c
>> @@ -104,7 +104,7 @@ static int meson_encoder_cvbs_get_modes(struct 
>> drm_bridge *bridge,
>>       for (i = 0; i < MESON_CVBS_MODES_COUNT; ++i) {
>>           struct meson_cvbs_mode *meson_mode = &meson_cvbs_modes[i];
>>   -        mode = drm_mode_duplicate(priv->drm, &meson_mode->mode);
>> +        mode = drm_mode_duplicate(&priv->drm, &meson_mode->mode);
>>           if (!mode) {
>>               dev_err(priv->dev, "Failed to create a new display 
>> mode\n");
>>               return 0;
>> @@ -221,7 +221,7 @@ static const struct drm_bridge_funcs 
>> meson_encoder_cvbs_bridge_funcs = {
>>     int meson_encoder_cvbs_probe(struct meson_drm *priv)
>>   {
>> -    struct drm_device *drm = priv->drm;
>> +    struct drm_device *drm = &priv->drm;
>>       struct meson_encoder_cvbs *meson_encoder_cvbs;
>>       struct drm_connector *connector;
>>       struct device_node *remote;
>> @@ -256,7 +256,7 @@ int meson_encoder_cvbs_probe(struct meson_drm *priv)
>>       meson_encoder_cvbs->priv = priv;
>>         /* Encoder */
>> -    ret = drm_simple_encoder_init(priv->drm, 
>> &meson_encoder_cvbs->encoder,
>> +    ret = drm_simple_encoder_init(&priv->drm, 
>> &meson_encoder_cvbs->encoder,
>>                         DRM_MODE_ENCODER_TVDAC);
>>       if (ret)
>>           return dev_err_probe(priv->dev, ret,
>> @@ -273,7 +273,7 @@ int meson_encoder_cvbs_probe(struct meson_drm *priv)
>>       }
>>         /* Initialize & attach Bridge Connector */
>> -    connector = drm_bridge_connector_init(priv->drm, 
>> &meson_encoder_cvbs->encoder);
>> +    connector = drm_bridge_connector_init(&priv->drm, 
>> &meson_encoder_cvbs->encoder);
>>       if (IS_ERR(connector))
>>           return dev_err_probe(priv->dev, PTR_ERR(connector),
>>                        "Unable to create CVBS bridge connector\n");
>> diff --git a/drivers/gpu/drm/meson/meson_overlay.c 
>> b/drivers/gpu/drm/meson/meson_overlay.c
>> index 7f98de38842b..60ee7f758723 100644
>> --- a/drivers/gpu/drm/meson/meson_overlay.c
>> +++ b/drivers/gpu/drm/meson/meson_overlay.c
>> @@ -484,7 +484,7 @@ static void meson_overlay_atomic_update(struct 
>> drm_plane *plane,
>>         interlace_mode = new_state->crtc->mode.flags & 
>> DRM_MODE_FLAG_INTERLACE;
>>   -    spin_lock_irqsave(&priv->drm->event_lock, flags);
>> +    spin_lock_irqsave(&priv->drm.event_lock, flags);
>>         if ((fb->modifier & DRM_FORMAT_MOD_AMLOGIC_FBC(0, 0)) ==
>>                   DRM_FORMAT_MOD_AMLOGIC_FBC(0, 0)) {
>> @@ -717,7 +717,7 @@ static void meson_overlay_atomic_update(struct 
>> drm_plane *plane,
>>         priv->viu.vd1_enabled = true;
>>   -    spin_unlock_irqrestore(&priv->drm->event_lock, flags);
>> +    spin_unlock_irqrestore(&priv->drm.event_lock, flags);
>>         DRM_DEBUG_DRIVER("\n");
>>   }
>> @@ -838,7 +838,7 @@ int meson_overlay_create(struct meson_drm *priv)
>>         DRM_DEBUG_DRIVER("\n");
>>   -    meson_overlay = devm_kzalloc(priv->drm->dev, 
>> sizeof(*meson_overlay),
>> +    meson_overlay = devm_kzalloc(priv->drm.dev, sizeof(*meson_overlay),
>>                      GFP_KERNEL);
>>       if (!meson_overlay)
>>           return -ENOMEM;
>> @@ -846,7 +846,7 @@ int meson_overlay_create(struct meson_drm *priv)
>>       meson_overlay->priv = priv;
>>       plane = &meson_overlay->base;
>>   -    drm_universal_plane_init(priv->drm, plane, 0xFF,
>> +    drm_universal_plane_init(&priv->drm, plane, 0xFF,
>>                    &meson_overlay_funcs,
>>                    supported_drm_formats,
>>                    ARRAY_SIZE(supported_drm_formats),
>> diff --git a/drivers/gpu/drm/meson/meson_plane.c 
>> b/drivers/gpu/drm/meson/meson_plane.c
>> index b43ac61201f3..13be94309bf4 100644
>> --- a/drivers/gpu/drm/meson/meson_plane.c
>> +++ b/drivers/gpu/drm/meson/meson_plane.c
>> @@ -157,7 +157,7 @@ static void meson_plane_atomic_update(struct 
>> drm_plane *plane,
>>        * Update Buffer
>>        * Enable Plane
>>        */
>> -    spin_lock_irqsave(&priv->drm->event_lock, flags);
>> +    spin_lock_irqsave(&priv->drm.event_lock, flags);
>>         /* Check if AFBC decoder is required for this buffer */
>>       if ((meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM) ||
>> @@ -393,7 +393,7 @@ static void meson_plane_atomic_update(struct 
>> drm_plane *plane,
>>         priv->viu.osd1_enabled = true;
>>   -    spin_unlock_irqrestore(&priv->drm->event_lock, flags);
>> +    spin_unlock_irqrestore(&priv->drm.event_lock, flags);
>>   }
>>     static void meson_plane_atomic_disable(struct drm_plane *plane,
>> @@ -536,7 +536,7 @@ int meson_plane_create(struct meson_drm *priv)
>>       const uint64_t *format_modifiers = format_modifiers_default;
>>       int ret;
>>   -    meson_plane = devm_kzalloc(priv->drm->dev, sizeof(*meson_plane),
>> +    meson_plane = devm_kzalloc(priv->drm.dev, sizeof(*meson_plane),
>>                      GFP_KERNEL);
>>       if (!meson_plane)
>>           return -ENOMEM;
>> @@ -549,14 +549,14 @@ int meson_plane_create(struct meson_drm *priv)
>>       else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A))
>>           format_modifiers = format_modifiers_afbc_g12a;
>>   -    ret = drm_universal_plane_init(priv->drm, plane, 0xFF,
>> +    ret = drm_universal_plane_init(&priv->drm, plane, 0xFF,
>>                       &meson_plane_funcs,
>>                       supported_drm_formats,
>>                       ARRAY_SIZE(supported_drm_formats),
>>                       format_modifiers,
>>                       DRM_PLANE_TYPE_PRIMARY, "meson_primary_plane");
>>       if (ret) {
>> -        devm_kfree(priv->drm->dev, meson_plane);
>> +        devm_kfree(priv->drm.dev, meson_plane);
>>           return ret;
>>       }
>

Re: [PATCH] drm/meson: switch to a managed drm device
Posted by neil.armstrong@linaro.org 1 year, 3 months ago
On 30/08/2024 10:23, Anastasia Belova wrote:
> Hi,
> 
> 29/08/24 15:14, Neil Armstrong пишет:
>> Hi,
>>
>> On 28/08/2024 13:04, Anastasia Belova wrote:
>>> Switch to a managed drm device to cleanup some error handling
>>> and make future work easier.
>>>
>>> Fix dereference of NULL in meson_drv_bind_master by removing
>>> drm_dev_put(drm) before meson_encoder_*_remove where drm
>>> dereferenced.
>>
>> Please send the fix separately with a Fixes tag.
>>
> 
> This fix can't be separated from the patch. drm_dev_put may be
> removed only while switching to a managed drm. Otherwise
> a check could be added before calling meson_encoder_*_remove.
> But it would become redundant after switching to a managed drm.
> 
> I may send the second version of this patch with Fixes tag, so all
> changes could be applied to older versions.

Reading the currenrt code, component_unbind_all(dev, drm) is called
after drm_dev_put(drm), which is quite wrong aswell.

So perhaps we should keep the kref on drm  until component_unbind_all()
is called in the first case, no ?

Neil

> 
> Thanks,
> Anastasia Belova
> 
>> Thanks,
>> Neil
>>
>>>
>>> Co-developed by Linux Verification Center (linuxtesting.org).
>>>
>>> Signed-off-by: Anastasia Belova <abelova@astralinux.ru>
>>> ---
>>>   drivers/gpu/drm/meson/meson_crtc.c         | 10 +--
>>>   drivers/gpu/drm/meson/meson_drv.c          | 71 ++++++++++------------
>>>   drivers/gpu/drm/meson/meson_drv.h          |  2 +-
>>>   drivers/gpu/drm/meson/meson_encoder_cvbs.c |  8 +--
>>>   drivers/gpu/drm/meson/meson_overlay.c      |  8 +--
>>>   drivers/gpu/drm/meson/meson_plane.c        | 10 +--
>>>   6 files changed, 51 insertions(+), 58 deletions(-)
>>>
>>> diff --git a/drivers/gpu/drm/meson/meson_crtc.c b/drivers/gpu/drm/meson/meson_crtc.c
>>> index d70616da8ce2..e1c0bf3baeea 100644
>>> --- a/drivers/gpu/drm/meson/meson_crtc.c
>>> +++ b/drivers/gpu/drm/meson/meson_crtc.c
>>> @@ -662,13 +662,13 @@ void meson_crtc_irq(struct meson_drm *priv)
>>>         drm_crtc_handle_vblank(priv->crtc);
>>>   -    spin_lock_irqsave(&priv->drm->event_lock, flags);
>>> +    spin_lock_irqsave(&priv->drm.event_lock, flags);
>>>       if (meson_crtc->event) {
>>>           drm_crtc_send_vblank_event(priv->crtc, meson_crtc->event);
>>>           drm_crtc_vblank_put(priv->crtc);
>>>           meson_crtc->event = NULL;
>>>       }
>>> -    spin_unlock_irqrestore(&priv->drm->event_lock, flags);
>>> +    spin_unlock_irqrestore(&priv->drm.event_lock, flags);
>>>   }
>>>     int meson_crtc_create(struct meson_drm *priv)
>>> @@ -677,18 +677,18 @@ int meson_crtc_create(struct meson_drm *priv)
>>>       struct drm_crtc *crtc;
>>>       int ret;
>>>   -    meson_crtc = devm_kzalloc(priv->drm->dev, sizeof(*meson_crtc),
>>> +    meson_crtc = devm_kzalloc(priv->drm.dev, sizeof(*meson_crtc),
>>>                     GFP_KERNEL);
>>>       if (!meson_crtc)
>>>           return -ENOMEM;
>>>         meson_crtc->priv = priv;
>>>       crtc = &meson_crtc->base;
>>> -    ret = drm_crtc_init_with_planes(priv->drm, crtc,
>>> +    ret = drm_crtc_init_with_planes(&priv->drm, crtc,
>>>                       priv->primary_plane, NULL,
>>>                       &meson_crtc_funcs, "meson_crtc");
>>>       if (ret) {
>>> -        dev_err(priv->drm->dev, "Failed to init CRTC\n");
>>> +        dev_err(priv->drm.dev, "Failed to init CRTC\n");
>>>           return ret;
>>>       }
>>>   diff --git a/drivers/gpu/drm/meson/meson_drv.c b/drivers/gpu/drm/meson/meson_drv.c
>>> index 4bd0baa2a4f5..2e7c2e7c7b82 100644
>>> --- a/drivers/gpu/drm/meson/meson_drv.c
>>> +++ b/drivers/gpu/drm/meson/meson_drv.c
>>> @@ -182,7 +182,6 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
>>>       struct platform_device *pdev = to_platform_device(dev);
>>>       const struct meson_drm_match_data *match;
>>>       struct meson_drm *priv;
>>> -    struct drm_device *drm;
>>>       struct resource *res;
>>>       void __iomem *regs;
>>>       int ret, i;
>>> @@ -197,17 +196,13 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
>>>       if (!match)
>>>           return -ENODEV;
>>>   -    drm = drm_dev_alloc(&meson_driver, dev);
>>> -    if (IS_ERR(drm))
>>> -        return PTR_ERR(drm);
>>> +    priv = devm_drm_dev_alloc(dev, &meson_driver,
>>> +                 struct meson_drm, drm);
>>>   -    priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
>>> -    if (!priv) {
>>> -        ret = -ENOMEM;
>>> -        goto free_drm;
>>> -    }
>>> -    drm->dev_private = priv;
>>> -    priv->drm = drm;
>>> +    if (IS_ERR(priv))
>>> +        return PTR_ERR(priv);
>>> +
>>> +    priv->drm.dev_private = priv;
>>>       priv->dev = dev;
>>>       priv->compat = match->compat;
>>>       priv->afbcd.ops = match->afbcd_ops;
>>> @@ -215,7 +210,7 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
>>>       regs = devm_platform_ioremap_resource_byname(pdev, "vpu");
>>>       if (IS_ERR(regs)) {
>>>           ret = PTR_ERR(regs);
>>> -        goto free_drm;
>>> +        goto remove_encoders;
>>>       }
>>>         priv->io_base = regs;
>>> @@ -223,13 +218,13 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
>>>       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "hhi");
>>>       if (!res) {
>>>           ret = -EINVAL;
>>> -        goto free_drm;
>>> +        goto remove_encoders;
>>>       }
>>>       /* Simply ioremap since it may be a shared register zone */
>>>       regs = devm_ioremap(dev, res->start, resource_size(res));
>>>       if (!regs) {
>>>           ret = -EADDRNOTAVAIL;
>>> -        goto free_drm;
>>> +        goto remove_encoders;
>>>       }
>>>         priv->hhi = devm_regmap_init_mmio(dev, regs,
>>> @@ -237,18 +232,18 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
>>>       if (IS_ERR(priv->hhi)) {
>>>           dev_err(&pdev->dev, "Couldn't create the HHI regmap\n");
>>>           ret = PTR_ERR(priv->hhi);
>>> -        goto free_drm;
>>> +        goto remove_encoders;
>>>       }
>>>         priv->canvas = meson_canvas_get(dev);
>>>       if (IS_ERR(priv->canvas)) {
>>>           ret = PTR_ERR(priv->canvas);
>>> -        goto free_drm;
>>> +        goto remove_encoders;
>>>       }
>>>         ret = meson_canvas_alloc(priv->canvas, &priv->canvas_id_osd1);
>>>       if (ret)
>>> -        goto free_drm;
>>> +        goto remove_encoders;
>>>       ret = meson_canvas_alloc(priv->canvas, &priv->canvas_id_vd1_0);
>>>       if (ret)
>>>           goto free_canvas_osd1;
>>> @@ -261,7 +256,7 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
>>>         priv->vsync_irq = platform_get_irq(pdev, 0);
>>>   -    ret = drm_vblank_init(drm, 1);
>>> +    ret = drm_vblank_init(&priv->drm, 1);
>>>       if (ret)
>>>           goto free_canvas_vd1_2;
>>>   @@ -284,10 +279,10 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
>>>       ret = drmm_mode_config_init(drm);
>>>       if (ret)
>>>           goto free_canvas_vd1_2;
>>> -    drm->mode_config.max_width = 3840;
>>> -    drm->mode_config.max_height = 2160;
>>> -    drm->mode_config.funcs = &meson_mode_config_funcs;
>>> -    drm->mode_config.helper_private    = &meson_mode_config_helpers;
>>> +    priv->drm.mode_config.max_width = 3840;
>>> +    priv->drm.mode_config.max_height = 2160;
>>> +    priv->drm.mode_config.funcs = &meson_mode_config_funcs;
>>> +    priv->drm.mode_config.helper_private = &meson_mode_config_helpers;
>>>         /* Hardware Initialization */
>>>   @@ -308,9 +303,9 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
>>>           goto exit_afbcd;
>>>         if (has_components) {
>>> -        ret = component_bind_all(dev, drm);
>>> +        ret = component_bind_all(dev, &priv->drm);
>>>           if (ret) {
>>> -            dev_err(drm->dev, "Couldn't bind all components\n");
>>> +            dev_err(priv->drm.dev, "Couldn't bind all components\n");
>>>               /* Do not try to unbind */
>>>               has_components = false;
>>>               goto exit_afbcd;
>>> @@ -339,26 +334,26 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
>>>       if (ret)
>>>           goto exit_afbcd;
>>>   -    ret = request_irq(priv->vsync_irq, meson_irq, 0, drm->driver->name, drm);
>>> +    ret = request_irq(priv->vsync_irq, meson_irq, 0, priv->drm.driver->name, &priv->drm);
>>>       if (ret)
>>>           goto exit_afbcd;
>>>   -    drm_mode_config_reset(drm);
>>> +    drm_mode_config_reset(&priv->drm);
>>>   -    drm_kms_helper_poll_init(drm);
>>> +    drm_kms_helper_poll_init(&priv->drm);
>>>         platform_set_drvdata(pdev, priv);
>>>   -    ret = drm_dev_register(drm, 0);
>>> +    ret = drm_dev_register(&priv->drm, 0);
>>>       if (ret)
>>>           goto uninstall_irq;
>>>   -    drm_fbdev_dma_setup(drm, 32);
>>> +    drm_fbdev_dma_setup(&priv->drm, 32);
>>>         return 0;
>>>     uninstall_irq:
>>> -    free_irq(priv->vsync_irq, drm);
>>> +    free_irq(priv->vsync_irq, &priv->drm);
>>>   exit_afbcd:
>>>       if (priv->afbcd.ops)
>>>           priv->afbcd.ops->exit(priv);
>>> @@ -370,15 +365,14 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
>>>       meson_canvas_free(priv->canvas, priv->canvas_id_vd1_0);
>>>   free_canvas_osd1:
>>>       meson_canvas_free(priv->canvas, priv->canvas_id_osd1);
>>> -free_drm:
>>> -    drm_dev_put(drm);
>>> +remove_encoders:
>>>         meson_encoder_dsi_remove(priv);
>>>       meson_encoder_hdmi_remove(priv);
>>>       meson_encoder_cvbs_remove(priv);
>>>         if (has_components)
>>> -        component_unbind_all(dev, drm);
>>> +        component_unbind_all(dev, &priv->drm);
>>>         return ret;
>>>   }
>>> @@ -391,7 +385,7 @@ static int meson_drv_bind(struct device *dev)
>>>   static void meson_drv_unbind(struct device *dev)
>>>   {
>>>       struct meson_drm *priv = dev_get_drvdata(dev);
>>> -    struct drm_device *drm = priv->drm;
>>> +    struct drm_device *drm = &priv->drm;
>>>         if (priv->canvas) {
>>>           meson_canvas_free(priv->canvas, priv->canvas_id_osd1);
>>> @@ -404,7 +398,6 @@ static void meson_drv_unbind(struct device *dev)
>>>       drm_kms_helper_poll_fini(drm);
>>>       drm_atomic_helper_shutdown(drm);
>>>       free_irq(priv->vsync_irq, drm);
>>> -    drm_dev_put(drm);
>>>         meson_encoder_dsi_remove(priv);
>>>       meson_encoder_hdmi_remove(priv);
>>> @@ -428,7 +421,7 @@ static int __maybe_unused meson_drv_pm_suspend(struct device *dev)
>>>       if (!priv)
>>>           return 0;
>>>   -    return drm_mode_config_helper_suspend(priv->drm);
>>> +    return drm_mode_config_helper_suspend(&priv->drm);
>>>   }
>>>     static int __maybe_unused meson_drv_pm_resume(struct device *dev)
>>> @@ -445,7 +438,7 @@ static int __maybe_unused meson_drv_pm_resume(struct device *dev)
>>>       if (priv->afbcd.ops)
>>>           priv->afbcd.ops->init(priv);
>>>   -    return drm_mode_config_helper_resume(priv->drm);
>>> +    return drm_mode_config_helper_resume(&priv->drm);
>>>   }
>>>     static void meson_drv_shutdown(struct platform_device *pdev)
>>> @@ -455,8 +448,8 @@ static void meson_drv_shutdown(struct platform_device *pdev)
>>>       if (!priv)
>>>           return;
>>>   -    drm_kms_helper_poll_fini(priv->drm);
>>> -    drm_atomic_helper_shutdown(priv->drm);
>>> +    drm_kms_helper_poll_fini(&priv->drm);
>>> +    drm_atomic_helper_shutdown(&priv->drm);
>>>   }
>>>     /*
>>> diff --git a/drivers/gpu/drm/meson/meson_drv.h b/drivers/gpu/drm/meson/meson_drv.h
>>> index 3f9345c14f31..c4c6c810cb20 100644
>>> --- a/drivers/gpu/drm/meson/meson_drv.h
>>> +++ b/drivers/gpu/drm/meson/meson_drv.h
>>> @@ -53,7 +53,7 @@ struct meson_drm {
>>>       u8 canvas_id_vd1_1;
>>>       u8 canvas_id_vd1_2;
>>>   -    struct drm_device *drm;
>>> +    struct drm_device drm;
>>>       struct drm_crtc *crtc;
>>>       struct drm_plane *primary_plane;
>>>       struct drm_plane *overlay_plane;
>>> diff --git a/drivers/gpu/drm/meson/meson_encoder_cvbs.c b/drivers/gpu/drm/meson/meson_encoder_cvbs.c
>>> index d1191de855d9..ddca22c8c1ff 100644
>>> --- a/drivers/gpu/drm/meson/meson_encoder_cvbs.c
>>> +++ b/drivers/gpu/drm/meson/meson_encoder_cvbs.c
>>> @@ -104,7 +104,7 @@ static int meson_encoder_cvbs_get_modes(struct drm_bridge *bridge,
>>>       for (i = 0; i < MESON_CVBS_MODES_COUNT; ++i) {
>>>           struct meson_cvbs_mode *meson_mode = &meson_cvbs_modes[i];
>>>   -        mode = drm_mode_duplicate(priv->drm, &meson_mode->mode);
>>> +        mode = drm_mode_duplicate(&priv->drm, &meson_mode->mode);
>>>           if (!mode) {
>>>               dev_err(priv->dev, "Failed to create a new display mode\n");
>>>               return 0;
>>> @@ -221,7 +221,7 @@ static const struct drm_bridge_funcs meson_encoder_cvbs_bridge_funcs = {
>>>     int meson_encoder_cvbs_probe(struct meson_drm *priv)
>>>   {
>>> -    struct drm_device *drm = priv->drm;
>>> +    struct drm_device *drm = &priv->drm;
>>>       struct meson_encoder_cvbs *meson_encoder_cvbs;
>>>       struct drm_connector *connector;
>>>       struct device_node *remote;
>>> @@ -256,7 +256,7 @@ int meson_encoder_cvbs_probe(struct meson_drm *priv)
>>>       meson_encoder_cvbs->priv = priv;
>>>         /* Encoder */
>>> -    ret = drm_simple_encoder_init(priv->drm, &meson_encoder_cvbs->encoder,
>>> +    ret = drm_simple_encoder_init(&priv->drm, &meson_encoder_cvbs->encoder,
>>>                         DRM_MODE_ENCODER_TVDAC);
>>>       if (ret)
>>>           return dev_err_probe(priv->dev, ret,
>>> @@ -273,7 +273,7 @@ int meson_encoder_cvbs_probe(struct meson_drm *priv)
>>>       }
>>>         /* Initialize & attach Bridge Connector */
>>> -    connector = drm_bridge_connector_init(priv->drm, &meson_encoder_cvbs->encoder);
>>> +    connector = drm_bridge_connector_init(&priv->drm, &meson_encoder_cvbs->encoder);
>>>       if (IS_ERR(connector))
>>>           return dev_err_probe(priv->dev, PTR_ERR(connector),
>>>                        "Unable to create CVBS bridge connector\n");
>>> diff --git a/drivers/gpu/drm/meson/meson_overlay.c b/drivers/gpu/drm/meson/meson_overlay.c
>>> index 7f98de38842b..60ee7f758723 100644
>>> --- a/drivers/gpu/drm/meson/meson_overlay.c
>>> +++ b/drivers/gpu/drm/meson/meson_overlay.c
>>> @@ -484,7 +484,7 @@ static void meson_overlay_atomic_update(struct drm_plane *plane,
>>>         interlace_mode = new_state->crtc->mode.flags & DRM_MODE_FLAG_INTERLACE;
>>>   -    spin_lock_irqsave(&priv->drm->event_lock, flags);
>>> +    spin_lock_irqsave(&priv->drm.event_lock, flags);
>>>         if ((fb->modifier & DRM_FORMAT_MOD_AMLOGIC_FBC(0, 0)) ==
>>>                   DRM_FORMAT_MOD_AMLOGIC_FBC(0, 0)) {
>>> @@ -717,7 +717,7 @@ static void meson_overlay_atomic_update(struct drm_plane *plane,
>>>         priv->viu.vd1_enabled = true;
>>>   -    spin_unlock_irqrestore(&priv->drm->event_lock, flags);
>>> +    spin_unlock_irqrestore(&priv->drm.event_lock, flags);
>>>         DRM_DEBUG_DRIVER("\n");
>>>   }
>>> @@ -838,7 +838,7 @@ int meson_overlay_create(struct meson_drm *priv)
>>>         DRM_DEBUG_DRIVER("\n");
>>>   -    meson_overlay = devm_kzalloc(priv->drm->dev, sizeof(*meson_overlay),
>>> +    meson_overlay = devm_kzalloc(priv->drm.dev, sizeof(*meson_overlay),
>>>                      GFP_KERNEL);
>>>       if (!meson_overlay)
>>>           return -ENOMEM;
>>> @@ -846,7 +846,7 @@ int meson_overlay_create(struct meson_drm *priv)
>>>       meson_overlay->priv = priv;
>>>       plane = &meson_overlay->base;
>>>   -    drm_universal_plane_init(priv->drm, plane, 0xFF,
>>> +    drm_universal_plane_init(&priv->drm, plane, 0xFF,
>>>                    &meson_overlay_funcs,
>>>                    supported_drm_formats,
>>>                    ARRAY_SIZE(supported_drm_formats),
>>> diff --git a/drivers/gpu/drm/meson/meson_plane.c b/drivers/gpu/drm/meson/meson_plane.c
>>> index b43ac61201f3..13be94309bf4 100644
>>> --- a/drivers/gpu/drm/meson/meson_plane.c
>>> +++ b/drivers/gpu/drm/meson/meson_plane.c
>>> @@ -157,7 +157,7 @@ static void meson_plane_atomic_update(struct drm_plane *plane,
>>>        * Update Buffer
>>>        * Enable Plane
>>>        */
>>> -    spin_lock_irqsave(&priv->drm->event_lock, flags);
>>> +    spin_lock_irqsave(&priv->drm.event_lock, flags);
>>>         /* Check if AFBC decoder is required for this buffer */
>>>       if ((meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM) ||
>>> @@ -393,7 +393,7 @@ static void meson_plane_atomic_update(struct drm_plane *plane,
>>>         priv->viu.osd1_enabled = true;
>>>   -    spin_unlock_irqrestore(&priv->drm->event_lock, flags);
>>> +    spin_unlock_irqrestore(&priv->drm.event_lock, flags);
>>>   }
>>>     static void meson_plane_atomic_disable(struct drm_plane *plane,
>>> @@ -536,7 +536,7 @@ int meson_plane_create(struct meson_drm *priv)
>>>       const uint64_t *format_modifiers = format_modifiers_default;
>>>       int ret;
>>>   -    meson_plane = devm_kzalloc(priv->drm->dev, sizeof(*meson_plane),
>>> +    meson_plane = devm_kzalloc(priv->drm.dev, sizeof(*meson_plane),
>>>                      GFP_KERNEL);
>>>       if (!meson_plane)
>>>           return -ENOMEM;
>>> @@ -549,14 +549,14 @@ int meson_plane_create(struct meson_drm *priv)
>>>       else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A))
>>>           format_modifiers = format_modifiers_afbc_g12a;
>>>   -    ret = drm_universal_plane_init(priv->drm, plane, 0xFF,
>>> +    ret = drm_universal_plane_init(&priv->drm, plane, 0xFF,
>>>                       &meson_plane_funcs,
>>>                       supported_drm_formats,
>>>                       ARRAY_SIZE(supported_drm_formats),
>>>                       format_modifiers,
>>>                       DRM_PLANE_TYPE_PRIMARY, "meson_primary_plane");
>>>       if (ret) {
>>> -        devm_kfree(priv->drm->dev, meson_plane);
>>> +        devm_kfree(priv->drm.dev, meson_plane);
>>>           return ret;
>>>       }
>>
> 

Re: [PATCH] drm/meson: switch to a managed drm device
Posted by Anastasia Belova 1 year, 3 months ago
Hi,

30/08/24 11:29, neil.armstrong@linaro.org пишет:
> On 30/08/2024 10:23, Anastasia Belova wrote:
>> Hi,
>>
>> 29/08/24 15:14, Neil Armstrong пишет:
>>> Hi,
>>>
>>> On 28/08/2024 13:04, Anastasia Belova wrote:
>>>> Switch to a managed drm device to cleanup some error handling
>>>> and make future work easier.
>>>>
>>>> Fix dereference of NULL in meson_drv_bind_master by removing
>>>> drm_dev_put(drm) before meson_encoder_*_remove where drm
>>>> dereferenced.
>>>
>>> Please send the fix separately with a Fixes tag.
>>>
>>
>> This fix can't be separated from the patch. drm_dev_put may be
>> removed only while switching to a managed drm. Otherwise
>> a check could be added before calling meson_encoder_*_remove.
>> But it would become redundant after switching to a managed drm.
>>
>> I may send the second version of this patch with Fixes tag, so all
>> changes could be applied to older versions.
>
> Reading the currenrt code, component_unbind_all(dev, drm) is called
> after drm_dev_put(drm), which is quite wrong aswell.
>
> So perhaps we should keep the kref on drm  until component_unbind_all()
> is called in the first case, no ?

Right, but with a managed drm we don't need to release kref ourselves.

The comment for commit is not complete. Information about dereference
of NULL in component_unbind_all may be added in the second version, as
well as Fixes tag.

Anastasia Belova

>
> Neil
>
>>
>> Thanks,
>> Anastasia Belova
>>
>>> Thanks,
>>> Neil
>>>
>>>>
>>>> Co-developed by Linux Verification Center (linuxtesting.org).
>>>>
>>>> Signed-off-by: Anastasia Belova <abelova@astralinux.ru>
>>>> ---
>>>>   drivers/gpu/drm/meson/meson_crtc.c         | 10 +--
>>>>   drivers/gpu/drm/meson/meson_drv.c          | 71 
>>>> ++++++++++------------
>>>>   drivers/gpu/drm/meson/meson_drv.h          |  2 +-
>>>>   drivers/gpu/drm/meson/meson_encoder_cvbs.c |  8 +--
>>>>   drivers/gpu/drm/meson/meson_overlay.c      |  8 +--
>>>>   drivers/gpu/drm/meson/meson_plane.c        | 10 +--
>>>>   6 files changed, 51 insertions(+), 58 deletions(-)
>>>>
>>>> diff --git a/drivers/gpu/drm/meson/meson_crtc.c 
>>>> b/drivers/gpu/drm/meson/meson_crtc.c
>>>> index d70616da8ce2..e1c0bf3baeea 100644
>>>> --- a/drivers/gpu/drm/meson/meson_crtc.c
>>>> +++ b/drivers/gpu/drm/meson/meson_crtc.c
>>>> @@ -662,13 +662,13 @@ void meson_crtc_irq(struct meson_drm *priv)
>>>>         drm_crtc_handle_vblank(priv->crtc);
>>>>   -    spin_lock_irqsave(&priv->drm->event_lock, flags);
>>>> +    spin_lock_irqsave(&priv->drm.event_lock, flags);
>>>>       if (meson_crtc->event) {
>>>>           drm_crtc_send_vblank_event(priv->crtc, meson_crtc->event);
>>>>           drm_crtc_vblank_put(priv->crtc);
>>>>           meson_crtc->event = NULL;
>>>>       }
>>>> - spin_unlock_irqrestore(&priv->drm->event_lock, flags);
>>>> +    spin_unlock_irqrestore(&priv->drm.event_lock, flags);
>>>>   }
>>>>     int meson_crtc_create(struct meson_drm *priv)
>>>> @@ -677,18 +677,18 @@ int meson_crtc_create(struct meson_drm *priv)
>>>>       struct drm_crtc *crtc;
>>>>       int ret;
>>>>   -    meson_crtc = devm_kzalloc(priv->drm->dev, sizeof(*meson_crtc),
>>>> +    meson_crtc = devm_kzalloc(priv->drm.dev, sizeof(*meson_crtc),
>>>>                     GFP_KERNEL);
>>>>       if (!meson_crtc)
>>>>           return -ENOMEM;
>>>>         meson_crtc->priv = priv;
>>>>       crtc = &meson_crtc->base;
>>>> -    ret = drm_crtc_init_with_planes(priv->drm, crtc,
>>>> +    ret = drm_crtc_init_with_planes(&priv->drm, crtc,
>>>>                       priv->primary_plane, NULL,
>>>>                       &meson_crtc_funcs, "meson_crtc");
>>>>       if (ret) {
>>>> -        dev_err(priv->drm->dev, "Failed to init CRTC\n");
>>>> +        dev_err(priv->drm.dev, "Failed to init CRTC\n");
>>>>           return ret;
>>>>       }
>>>>   diff --git a/drivers/gpu/drm/meson/meson_drv.c 
>>>> b/drivers/gpu/drm/meson/meson_drv.c
>>>> index 4bd0baa2a4f5..2e7c2e7c7b82 100644
>>>> --- a/drivers/gpu/drm/meson/meson_drv.c
>>>> +++ b/drivers/gpu/drm/meson/meson_drv.c
>>>> @@ -182,7 +182,6 @@ static int meson_drv_bind_master(struct device 
>>>> *dev, bool has_components)
>>>>       struct platform_device *pdev = to_platform_device(dev);
>>>>       const struct meson_drm_match_data *match;
>>>>       struct meson_drm *priv;
>>>> -    struct drm_device *drm;
>>>>       struct resource *res;
>>>>       void __iomem *regs;
>>>>       int ret, i;
>>>> @@ -197,17 +196,13 @@ static int meson_drv_bind_master(struct 
>>>> device *dev, bool has_components)
>>>>       if (!match)
>>>>           return -ENODEV;
>>>>   -    drm = drm_dev_alloc(&meson_driver, dev);
>>>> -    if (IS_ERR(drm))
>>>> -        return PTR_ERR(drm);
>>>> +    priv = devm_drm_dev_alloc(dev, &meson_driver,
>>>> +                 struct meson_drm, drm);
>>>>   -    priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
>>>> -    if (!priv) {
>>>> -        ret = -ENOMEM;
>>>> -        goto free_drm;
>>>> -    }
>>>> -    drm->dev_private = priv;
>>>> -    priv->drm = drm;
>>>> +    if (IS_ERR(priv))
>>>> +        return PTR_ERR(priv);
>>>> +
>>>> +    priv->drm.dev_private = priv;
>>>>       priv->dev = dev;
>>>>       priv->compat = match->compat;
>>>>       priv->afbcd.ops = match->afbcd_ops;
>>>> @@ -215,7 +210,7 @@ static int meson_drv_bind_master(struct device 
>>>> *dev, bool has_components)
>>>>       regs = devm_platform_ioremap_resource_byname(pdev, "vpu");
>>>>       if (IS_ERR(regs)) {
>>>>           ret = PTR_ERR(regs);
>>>> -        goto free_drm;
>>>> +        goto remove_encoders;
>>>>       }
>>>>         priv->io_base = regs;
>>>> @@ -223,13 +218,13 @@ static int meson_drv_bind_master(struct 
>>>> device *dev, bool has_components)
>>>>       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "hhi");
>>>>       if (!res) {
>>>>           ret = -EINVAL;
>>>> -        goto free_drm;
>>>> +        goto remove_encoders;
>>>>       }
>>>>       /* Simply ioremap since it may be a shared register zone */
>>>>       regs = devm_ioremap(dev, res->start, resource_size(res));
>>>>       if (!regs) {
>>>>           ret = -EADDRNOTAVAIL;
>>>> -        goto free_drm;
>>>> +        goto remove_encoders;
>>>>       }
>>>>         priv->hhi = devm_regmap_init_mmio(dev, regs,
>>>> @@ -237,18 +232,18 @@ static int meson_drv_bind_master(struct 
>>>> device *dev, bool has_components)
>>>>       if (IS_ERR(priv->hhi)) {
>>>>           dev_err(&pdev->dev, "Couldn't create the HHI regmap\n");
>>>>           ret = PTR_ERR(priv->hhi);
>>>> -        goto free_drm;
>>>> +        goto remove_encoders;
>>>>       }
>>>>         priv->canvas = meson_canvas_get(dev);
>>>>       if (IS_ERR(priv->canvas)) {
>>>>           ret = PTR_ERR(priv->canvas);
>>>> -        goto free_drm;
>>>> +        goto remove_encoders;
>>>>       }
>>>>         ret = meson_canvas_alloc(priv->canvas, &priv->canvas_id_osd1);
>>>>       if (ret)
>>>> -        goto free_drm;
>>>> +        goto remove_encoders;
>>>>       ret = meson_canvas_alloc(priv->canvas, &priv->canvas_id_vd1_0);
>>>>       if (ret)
>>>>           goto free_canvas_osd1;
>>>> @@ -261,7 +256,7 @@ static int meson_drv_bind_master(struct device 
>>>> *dev, bool has_components)
>>>>         priv->vsync_irq = platform_get_irq(pdev, 0);
>>>>   -    ret = drm_vblank_init(drm, 1);
>>>> +    ret = drm_vblank_init(&priv->drm, 1);
>>>>       if (ret)
>>>>           goto free_canvas_vd1_2;
>>>>   @@ -284,10 +279,10 @@ static int meson_drv_bind_master(struct 
>>>> device *dev, bool has_components)
>>>>       ret = drmm_mode_config_init(drm);
>>>>       if (ret)
>>>>           goto free_canvas_vd1_2;
>>>> -    drm->mode_config.max_width = 3840;
>>>> -    drm->mode_config.max_height = 2160;
>>>> -    drm->mode_config.funcs = &meson_mode_config_funcs;
>>>> -    drm->mode_config.helper_private    = &meson_mode_config_helpers;
>>>> +    priv->drm.mode_config.max_width = 3840;
>>>> +    priv->drm.mode_config.max_height = 2160;
>>>> +    priv->drm.mode_config.funcs = &meson_mode_config_funcs;
>>>> +    priv->drm.mode_config.helper_private = 
>>>> &meson_mode_config_helpers;
>>>>         /* Hardware Initialization */
>>>>   @@ -308,9 +303,9 @@ static int meson_drv_bind_master(struct 
>>>> device *dev, bool has_components)
>>>>           goto exit_afbcd;
>>>>         if (has_components) {
>>>> -        ret = component_bind_all(dev, drm);
>>>> +        ret = component_bind_all(dev, &priv->drm);
>>>>           if (ret) {
>>>> -            dev_err(drm->dev, "Couldn't bind all components\n");
>>>> +            dev_err(priv->drm.dev, "Couldn't bind all components\n");
>>>>               /* Do not try to unbind */
>>>>               has_components = false;
>>>>               goto exit_afbcd;
>>>> @@ -339,26 +334,26 @@ static int meson_drv_bind_master(struct 
>>>> device *dev, bool has_components)
>>>>       if (ret)
>>>>           goto exit_afbcd;
>>>>   -    ret = request_irq(priv->vsync_irq, meson_irq, 0, 
>>>> drm->driver->name, drm);
>>>> +    ret = request_irq(priv->vsync_irq, meson_irq, 0, 
>>>> priv->drm.driver->name, &priv->drm);
>>>>       if (ret)
>>>>           goto exit_afbcd;
>>>>   -    drm_mode_config_reset(drm);
>>>> +    drm_mode_config_reset(&priv->drm);
>>>>   -    drm_kms_helper_poll_init(drm);
>>>> +    drm_kms_helper_poll_init(&priv->drm);
>>>>         platform_set_drvdata(pdev, priv);
>>>>   -    ret = drm_dev_register(drm, 0);
>>>> +    ret = drm_dev_register(&priv->drm, 0);
>>>>       if (ret)
>>>>           goto uninstall_irq;
>>>>   -    drm_fbdev_dma_setup(drm, 32);
>>>> +    drm_fbdev_dma_setup(&priv->drm, 32);
>>>>         return 0;
>>>>     uninstall_irq:
>>>> -    free_irq(priv->vsync_irq, drm);
>>>> +    free_irq(priv->vsync_irq, &priv->drm);
>>>>   exit_afbcd:
>>>>       if (priv->afbcd.ops)
>>>>           priv->afbcd.ops->exit(priv);
>>>> @@ -370,15 +365,14 @@ static int meson_drv_bind_master(struct 
>>>> device *dev, bool has_components)
>>>>       meson_canvas_free(priv->canvas, priv->canvas_id_vd1_0);
>>>>   free_canvas_osd1:
>>>>       meson_canvas_free(priv->canvas, priv->canvas_id_osd1);
>>>> -free_drm:
>>>> -    drm_dev_put(drm);
>>>> +remove_encoders:
>>>>         meson_encoder_dsi_remove(priv);
>>>>       meson_encoder_hdmi_remove(priv);
>>>>       meson_encoder_cvbs_remove(priv);
>>>>         if (has_components)
>>>> -        component_unbind_all(dev, drm);
>>>> +        component_unbind_all(dev, &priv->drm);
>>>>         return ret;
>>>>   }
>>>> @@ -391,7 +385,7 @@ static int meson_drv_bind(struct device *dev)
>>>>   static void meson_drv_unbind(struct device *dev)
>>>>   {
>>>>       struct meson_drm *priv = dev_get_drvdata(dev);
>>>> -    struct drm_device *drm = priv->drm;
>>>> +    struct drm_device *drm = &priv->drm;
>>>>         if (priv->canvas) {
>>>>           meson_canvas_free(priv->canvas, priv->canvas_id_osd1);
>>>> @@ -404,7 +398,6 @@ static void meson_drv_unbind(struct device *dev)
>>>>       drm_kms_helper_poll_fini(drm);
>>>>       drm_atomic_helper_shutdown(drm);
>>>>       free_irq(priv->vsync_irq, drm);
>>>> -    drm_dev_put(drm);
>>>>         meson_encoder_dsi_remove(priv);
>>>>       meson_encoder_hdmi_remove(priv);
>>>> @@ -428,7 +421,7 @@ static int __maybe_unused 
>>>> meson_drv_pm_suspend(struct device *dev)
>>>>       if (!priv)
>>>>           return 0;
>>>>   -    return drm_mode_config_helper_suspend(priv->drm);
>>>> +    return drm_mode_config_helper_suspend(&priv->drm);
>>>>   }
>>>>     static int __maybe_unused meson_drv_pm_resume(struct device *dev)
>>>> @@ -445,7 +438,7 @@ static int __maybe_unused 
>>>> meson_drv_pm_resume(struct device *dev)
>>>>       if (priv->afbcd.ops)
>>>>           priv->afbcd.ops->init(priv);
>>>>   -    return drm_mode_config_helper_resume(priv->drm);
>>>> +    return drm_mode_config_helper_resume(&priv->drm);
>>>>   }
>>>>     static void meson_drv_shutdown(struct platform_device *pdev)
>>>> @@ -455,8 +448,8 @@ static void meson_drv_shutdown(struct 
>>>> platform_device *pdev)
>>>>       if (!priv)
>>>>           return;
>>>>   -    drm_kms_helper_poll_fini(priv->drm);
>>>> -    drm_atomic_helper_shutdown(priv->drm);
>>>> +    drm_kms_helper_poll_fini(&priv->drm);
>>>> +    drm_atomic_helper_shutdown(&priv->drm);
>>>>   }
>>>>     /*
>>>> diff --git a/drivers/gpu/drm/meson/meson_drv.h 
>>>> b/drivers/gpu/drm/meson/meson_drv.h
>>>> index 3f9345c14f31..c4c6c810cb20 100644
>>>> --- a/drivers/gpu/drm/meson/meson_drv.h
>>>> +++ b/drivers/gpu/drm/meson/meson_drv.h
>>>> @@ -53,7 +53,7 @@ struct meson_drm {
>>>>       u8 canvas_id_vd1_1;
>>>>       u8 canvas_id_vd1_2;
>>>>   -    struct drm_device *drm;
>>>> +    struct drm_device drm;
>>>>       struct drm_crtc *crtc;
>>>>       struct drm_plane *primary_plane;
>>>>       struct drm_plane *overlay_plane;
>>>> diff --git a/drivers/gpu/drm/meson/meson_encoder_cvbs.c 
>>>> b/drivers/gpu/drm/meson/meson_encoder_cvbs.c
>>>> index d1191de855d9..ddca22c8c1ff 100644
>>>> --- a/drivers/gpu/drm/meson/meson_encoder_cvbs.c
>>>> +++ b/drivers/gpu/drm/meson/meson_encoder_cvbs.c
>>>> @@ -104,7 +104,7 @@ static int meson_encoder_cvbs_get_modes(struct 
>>>> drm_bridge *bridge,
>>>>       for (i = 0; i < MESON_CVBS_MODES_COUNT; ++i) {
>>>>           struct meson_cvbs_mode *meson_mode = &meson_cvbs_modes[i];
>>>>   -        mode = drm_mode_duplicate(priv->drm, &meson_mode->mode);
>>>> +        mode = drm_mode_duplicate(&priv->drm, &meson_mode->mode);
>>>>           if (!mode) {
>>>>               dev_err(priv->dev, "Failed to create a new display 
>>>> mode\n");
>>>>               return 0;
>>>> @@ -221,7 +221,7 @@ static const struct drm_bridge_funcs 
>>>> meson_encoder_cvbs_bridge_funcs = {
>>>>     int meson_encoder_cvbs_probe(struct meson_drm *priv)
>>>>   {
>>>> -    struct drm_device *drm = priv->drm;
>>>> +    struct drm_device *drm = &priv->drm;
>>>>       struct meson_encoder_cvbs *meson_encoder_cvbs;
>>>>       struct drm_connector *connector;
>>>>       struct device_node *remote;
>>>> @@ -256,7 +256,7 @@ int meson_encoder_cvbs_probe(struct meson_drm 
>>>> *priv)
>>>>       meson_encoder_cvbs->priv = priv;
>>>>         /* Encoder */
>>>> -    ret = drm_simple_encoder_init(priv->drm, 
>>>> &meson_encoder_cvbs->encoder,
>>>> +    ret = drm_simple_encoder_init(&priv->drm, 
>>>> &meson_encoder_cvbs->encoder,
>>>>                         DRM_MODE_ENCODER_TVDAC);
>>>>       if (ret)
>>>>           return dev_err_probe(priv->dev, ret,
>>>> @@ -273,7 +273,7 @@ int meson_encoder_cvbs_probe(struct meson_drm 
>>>> *priv)
>>>>       }
>>>>         /* Initialize & attach Bridge Connector */
>>>> -    connector = drm_bridge_connector_init(priv->drm, 
>>>> &meson_encoder_cvbs->encoder);
>>>> +    connector = drm_bridge_connector_init(&priv->drm, 
>>>> &meson_encoder_cvbs->encoder);
>>>>       if (IS_ERR(connector))
>>>>           return dev_err_probe(priv->dev, PTR_ERR(connector),
>>>>                        "Unable to create CVBS bridge connector\n");
>>>> diff --git a/drivers/gpu/drm/meson/meson_overlay.c 
>>>> b/drivers/gpu/drm/meson/meson_overlay.c
>>>> index 7f98de38842b..60ee7f758723 100644
>>>> --- a/drivers/gpu/drm/meson/meson_overlay.c
>>>> +++ b/drivers/gpu/drm/meson/meson_overlay.c
>>>> @@ -484,7 +484,7 @@ static void meson_overlay_atomic_update(struct 
>>>> drm_plane *plane,
>>>>         interlace_mode = new_state->crtc->mode.flags & 
>>>> DRM_MODE_FLAG_INTERLACE;
>>>>   -    spin_lock_irqsave(&priv->drm->event_lock, flags);
>>>> +    spin_lock_irqsave(&priv->drm.event_lock, flags);
>>>>         if ((fb->modifier & DRM_FORMAT_MOD_AMLOGIC_FBC(0, 0)) ==
>>>>                   DRM_FORMAT_MOD_AMLOGIC_FBC(0, 0)) {
>>>> @@ -717,7 +717,7 @@ static void meson_overlay_atomic_update(struct 
>>>> drm_plane *plane,
>>>>         priv->viu.vd1_enabled = true;
>>>>   - spin_unlock_irqrestore(&priv->drm->event_lock, flags);
>>>> +    spin_unlock_irqrestore(&priv->drm.event_lock, flags);
>>>>         DRM_DEBUG_DRIVER("\n");
>>>>   }
>>>> @@ -838,7 +838,7 @@ int meson_overlay_create(struct meson_drm *priv)
>>>>         DRM_DEBUG_DRIVER("\n");
>>>>   -    meson_overlay = devm_kzalloc(priv->drm->dev, 
>>>> sizeof(*meson_overlay),
>>>> +    meson_overlay = devm_kzalloc(priv->drm.dev, 
>>>> sizeof(*meson_overlay),
>>>>                      GFP_KERNEL);
>>>>       if (!meson_overlay)
>>>>           return -ENOMEM;
>>>> @@ -846,7 +846,7 @@ int meson_overlay_create(struct meson_drm *priv)
>>>>       meson_overlay->priv = priv;
>>>>       plane = &meson_overlay->base;
>>>>   -    drm_universal_plane_init(priv->drm, plane, 0xFF,
>>>> +    drm_universal_plane_init(&priv->drm, plane, 0xFF,
>>>>                    &meson_overlay_funcs,
>>>>                    supported_drm_formats,
>>>>                    ARRAY_SIZE(supported_drm_formats),
>>>> diff --git a/drivers/gpu/drm/meson/meson_plane.c 
>>>> b/drivers/gpu/drm/meson/meson_plane.c
>>>> index b43ac61201f3..13be94309bf4 100644
>>>> --- a/drivers/gpu/drm/meson/meson_plane.c
>>>> +++ b/drivers/gpu/drm/meson/meson_plane.c
>>>> @@ -157,7 +157,7 @@ static void meson_plane_atomic_update(struct 
>>>> drm_plane *plane,
>>>>        * Update Buffer
>>>>        * Enable Plane
>>>>        */
>>>> -    spin_lock_irqsave(&priv->drm->event_lock, flags);
>>>> +    spin_lock_irqsave(&priv->drm.event_lock, flags);
>>>>         /* Check if AFBC decoder is required for this buffer */
>>>>       if ((meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM) ||
>>>> @@ -393,7 +393,7 @@ static void meson_plane_atomic_update(struct 
>>>> drm_plane *plane,
>>>>         priv->viu.osd1_enabled = true;
>>>>   - spin_unlock_irqrestore(&priv->drm->event_lock, flags);
>>>> +    spin_unlock_irqrestore(&priv->drm.event_lock, flags);
>>>>   }
>>>>     static void meson_plane_atomic_disable(struct drm_plane *plane,
>>>> @@ -536,7 +536,7 @@ int meson_plane_create(struct meson_drm *priv)
>>>>       const uint64_t *format_modifiers = format_modifiers_default;
>>>>       int ret;
>>>>   -    meson_plane = devm_kzalloc(priv->drm->dev, 
>>>> sizeof(*meson_plane),
>>>> +    meson_plane = devm_kzalloc(priv->drm.dev, sizeof(*meson_plane),
>>>>                      GFP_KERNEL);
>>>>       if (!meson_plane)
>>>>           return -ENOMEM;
>>>> @@ -549,14 +549,14 @@ int meson_plane_create(struct meson_drm *priv)
>>>>       else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A))
>>>>           format_modifiers = format_modifiers_afbc_g12a;
>>>>   -    ret = drm_universal_plane_init(priv->drm, plane, 0xFF,
>>>> +    ret = drm_universal_plane_init(&priv->drm, plane, 0xFF,
>>>>                       &meson_plane_funcs,
>>>>                       supported_drm_formats,
>>>>                       ARRAY_SIZE(supported_drm_formats),
>>>>                       format_modifiers,
>>>>                       DRM_PLANE_TYPE_PRIMARY, "meson_primary_plane");
>>>>       if (ret) {
>>>> -        devm_kfree(priv->drm->dev, meson_plane);
>>>> +        devm_kfree(priv->drm.dev, meson_plane);
>>>>           return ret;
>>>>       }
>>>
>>
>

[PATCH v2] drm/meson: switch to a managed drm device
Posted by Anastasia Belova 1 year, 3 months ago
Switch to a managed drm device to cleanup some error handling
and make future work easier.

Fix dereference of NULL in meson_drv_bind_master by removing
drm_dev_put(drm) before meson_encoder_*_remove and
component_unbind_all where drm is dereferenced.

Co-developed by Linux Verification Center (linuxtesting.org).

Cc: stable@vger.kernel.org # 6.5
Fixes: 6a044642988b ("drm/meson: fix unbind path if HDMI fails to bind")
Signed-off-by: Anastasia Belova <abelova@astralinux.ru>
---
v2: fix commit message and add Cc: stable@vger.kernel.org
 drivers/gpu/drm/meson/meson_crtc.c         | 10 +--
 drivers/gpu/drm/meson/meson_drv.c          | 71 ++++++++++------------
 drivers/gpu/drm/meson/meson_drv.h          |  2 +-
 drivers/gpu/drm/meson/meson_encoder_cvbs.c |  8 +--
 drivers/gpu/drm/meson/meson_overlay.c      |  8 +--
 drivers/gpu/drm/meson/meson_plane.c        | 10 +--
 6 files changed, 51 insertions(+), 58 deletions(-)

diff --git a/drivers/gpu/drm/meson/meson_crtc.c b/drivers/gpu/drm/meson/meson_crtc.c
index d70616da8ce2..e1c0bf3baeea 100644
--- a/drivers/gpu/drm/meson/meson_crtc.c
+++ b/drivers/gpu/drm/meson/meson_crtc.c
@@ -662,13 +662,13 @@ void meson_crtc_irq(struct meson_drm *priv)
 
 	drm_crtc_handle_vblank(priv->crtc);
 
-	spin_lock_irqsave(&priv->drm->event_lock, flags);
+	spin_lock_irqsave(&priv->drm.event_lock, flags);
 	if (meson_crtc->event) {
 		drm_crtc_send_vblank_event(priv->crtc, meson_crtc->event);
 		drm_crtc_vblank_put(priv->crtc);
 		meson_crtc->event = NULL;
 	}
-	spin_unlock_irqrestore(&priv->drm->event_lock, flags);
+	spin_unlock_irqrestore(&priv->drm.event_lock, flags);
 }
 
 int meson_crtc_create(struct meson_drm *priv)
@@ -677,18 +677,18 @@ int meson_crtc_create(struct meson_drm *priv)
 	struct drm_crtc *crtc;
 	int ret;
 
-	meson_crtc = devm_kzalloc(priv->drm->dev, sizeof(*meson_crtc),
+	meson_crtc = devm_kzalloc(priv->drm.dev, sizeof(*meson_crtc),
 				  GFP_KERNEL);
 	if (!meson_crtc)
 		return -ENOMEM;
 
 	meson_crtc->priv = priv;
 	crtc = &meson_crtc->base;
-	ret = drm_crtc_init_with_planes(priv->drm, crtc,
+	ret = drm_crtc_init_with_planes(&priv->drm, crtc,
 					priv->primary_plane, NULL,
 					&meson_crtc_funcs, "meson_crtc");
 	if (ret) {
-		dev_err(priv->drm->dev, "Failed to init CRTC\n");
+		dev_err(priv->drm.dev, "Failed to init CRTC\n");
 		return ret;
 	}
 
diff --git a/drivers/gpu/drm/meson/meson_drv.c b/drivers/gpu/drm/meson/meson_drv.c
index 4bd0baa2a4f5..2e7c2e7c7b82 100644
--- a/drivers/gpu/drm/meson/meson_drv.c
+++ b/drivers/gpu/drm/meson/meson_drv.c
@@ -182,7 +182,6 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
 	struct platform_device *pdev = to_platform_device(dev);
 	const struct meson_drm_match_data *match;
 	struct meson_drm *priv;
-	struct drm_device *drm;
 	struct resource *res;
 	void __iomem *regs;
 	int ret, i;
@@ -197,17 +196,13 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
 	if (!match)
 		return -ENODEV;
 
-	drm = drm_dev_alloc(&meson_driver, dev);
-	if (IS_ERR(drm))
-		return PTR_ERR(drm);
+	priv = devm_drm_dev_alloc(dev, &meson_driver,
+				 struct meson_drm, drm);
 
-	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
-	if (!priv) {
-		ret = -ENOMEM;
-		goto free_drm;
-	}
-	drm->dev_private = priv;
-	priv->drm = drm;
+	if (IS_ERR(priv))
+		return PTR_ERR(priv);
+
+	priv->drm.dev_private = priv;
 	priv->dev = dev;
 	priv->compat = match->compat;
 	priv->afbcd.ops = match->afbcd_ops;
@@ -215,7 +210,7 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
 	regs = devm_platform_ioremap_resource_byname(pdev, "vpu");
 	if (IS_ERR(regs)) {
 		ret = PTR_ERR(regs);
-		goto free_drm;
+		goto remove_encoders;
 	}
 
 	priv->io_base = regs;
@@ -223,13 +218,13 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "hhi");
 	if (!res) {
 		ret = -EINVAL;
-		goto free_drm;
+		goto remove_encoders;
 	}
 	/* Simply ioremap since it may be a shared register zone */
 	regs = devm_ioremap(dev, res->start, resource_size(res));
 	if (!regs) {
 		ret = -EADDRNOTAVAIL;
-		goto free_drm;
+		goto remove_encoders;
 	}
 
 	priv->hhi = devm_regmap_init_mmio(dev, regs,
@@ -237,18 +232,18 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
 	if (IS_ERR(priv->hhi)) {
 		dev_err(&pdev->dev, "Couldn't create the HHI regmap\n");
 		ret = PTR_ERR(priv->hhi);
-		goto free_drm;
+		goto remove_encoders;
 	}
 
 	priv->canvas = meson_canvas_get(dev);
 	if (IS_ERR(priv->canvas)) {
 		ret = PTR_ERR(priv->canvas);
-		goto free_drm;
+		goto remove_encoders;
 	}
 
 	ret = meson_canvas_alloc(priv->canvas, &priv->canvas_id_osd1);
 	if (ret)
-		goto free_drm;
+		goto remove_encoders;
 	ret = meson_canvas_alloc(priv->canvas, &priv->canvas_id_vd1_0);
 	if (ret)
 		goto free_canvas_osd1;
@@ -261,7 +256,7 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
 
 	priv->vsync_irq = platform_get_irq(pdev, 0);
 
-	ret = drm_vblank_init(drm, 1);
+	ret = drm_vblank_init(&priv->drm, 1);
 	if (ret)
 		goto free_canvas_vd1_2;
 
@@ -284,10 +279,10 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
 	ret = drmm_mode_config_init(drm);
 	if (ret)
 		goto free_canvas_vd1_2;
-	drm->mode_config.max_width = 3840;
-	drm->mode_config.max_height = 2160;
-	drm->mode_config.funcs = &meson_mode_config_funcs;
-	drm->mode_config.helper_private	= &meson_mode_config_helpers;
+	priv->drm.mode_config.max_width = 3840;
+	priv->drm.mode_config.max_height = 2160;
+	priv->drm.mode_config.funcs = &meson_mode_config_funcs;
+	priv->drm.mode_config.helper_private = &meson_mode_config_helpers;
 
 	/* Hardware Initialization */
 
@@ -308,9 +303,9 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
 		goto exit_afbcd;
 
 	if (has_components) {
-		ret = component_bind_all(dev, drm);
+		ret = component_bind_all(dev, &priv->drm);
 		if (ret) {
-			dev_err(drm->dev, "Couldn't bind all components\n");
+			dev_err(priv->drm.dev, "Couldn't bind all components\n");
 			/* Do not try to unbind */
 			has_components = false;
 			goto exit_afbcd;
@@ -339,26 +334,26 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
 	if (ret)
 		goto exit_afbcd;
 
-	ret = request_irq(priv->vsync_irq, meson_irq, 0, drm->driver->name, drm);
+	ret = request_irq(priv->vsync_irq, meson_irq, 0, priv->drm.driver->name, &priv->drm);
 	if (ret)
 		goto exit_afbcd;
 
-	drm_mode_config_reset(drm);
+	drm_mode_config_reset(&priv->drm);
 
-	drm_kms_helper_poll_init(drm);
+	drm_kms_helper_poll_init(&priv->drm);
 
 	platform_set_drvdata(pdev, priv);
 
-	ret = drm_dev_register(drm, 0);
+	ret = drm_dev_register(&priv->drm, 0);
 	if (ret)
 		goto uninstall_irq;
 
-	drm_fbdev_dma_setup(drm, 32);
+	drm_fbdev_dma_setup(&priv->drm, 32);
 
 	return 0;
 
 uninstall_irq:
-	free_irq(priv->vsync_irq, drm);
+	free_irq(priv->vsync_irq, &priv->drm);
 exit_afbcd:
 	if (priv->afbcd.ops)
 		priv->afbcd.ops->exit(priv);
@@ -370,15 +365,14 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
 	meson_canvas_free(priv->canvas, priv->canvas_id_vd1_0);
 free_canvas_osd1:
 	meson_canvas_free(priv->canvas, priv->canvas_id_osd1);
-free_drm:
-	drm_dev_put(drm);
+remove_encoders:
 
 	meson_encoder_dsi_remove(priv);
 	meson_encoder_hdmi_remove(priv);
 	meson_encoder_cvbs_remove(priv);
 
 	if (has_components)
-		component_unbind_all(dev, drm);
+		component_unbind_all(dev, &priv->drm);
 
 	return ret;
 }
@@ -391,7 +385,7 @@ static int meson_drv_bind(struct device *dev)
 static void meson_drv_unbind(struct device *dev)
 {
 	struct meson_drm *priv = dev_get_drvdata(dev);
-	struct drm_device *drm = priv->drm;
+	struct drm_device *drm = &priv->drm;
 
 	if (priv->canvas) {
 		meson_canvas_free(priv->canvas, priv->canvas_id_osd1);
@@ -404,7 +398,6 @@ static void meson_drv_unbind(struct device *dev)
 	drm_kms_helper_poll_fini(drm);
 	drm_atomic_helper_shutdown(drm);
 	free_irq(priv->vsync_irq, drm);
-	drm_dev_put(drm);
 
 	meson_encoder_dsi_remove(priv);
 	meson_encoder_hdmi_remove(priv);
@@ -428,7 +421,7 @@ static int __maybe_unused meson_drv_pm_suspend(struct device *dev)
 	if (!priv)
 		return 0;
 
-	return drm_mode_config_helper_suspend(priv->drm);
+	return drm_mode_config_helper_suspend(&priv->drm);
 }
 
 static int __maybe_unused meson_drv_pm_resume(struct device *dev)
@@ -445,7 +438,7 @@ static int __maybe_unused meson_drv_pm_resume(struct device *dev)
 	if (priv->afbcd.ops)
 		priv->afbcd.ops->init(priv);
 
-	return drm_mode_config_helper_resume(priv->drm);
+	return drm_mode_config_helper_resume(&priv->drm);
 }
 
 static void meson_drv_shutdown(struct platform_device *pdev)
@@ -455,8 +448,8 @@ static void meson_drv_shutdown(struct platform_device *pdev)
 	if (!priv)
 		return;
 
-	drm_kms_helper_poll_fini(priv->drm);
-	drm_atomic_helper_shutdown(priv->drm);
+	drm_kms_helper_poll_fini(&priv->drm);
+	drm_atomic_helper_shutdown(&priv->drm);
 }
 
 /*
diff --git a/drivers/gpu/drm/meson/meson_drv.h b/drivers/gpu/drm/meson/meson_drv.h
index 3f9345c14f31..c4c6c810cb20 100644
--- a/drivers/gpu/drm/meson/meson_drv.h
+++ b/drivers/gpu/drm/meson/meson_drv.h
@@ -53,7 +53,7 @@ struct meson_drm {
 	u8 canvas_id_vd1_1;
 	u8 canvas_id_vd1_2;
 
-	struct drm_device *drm;
+	struct drm_device drm;
 	struct drm_crtc *crtc;
 	struct drm_plane *primary_plane;
 	struct drm_plane *overlay_plane;
diff --git a/drivers/gpu/drm/meson/meson_encoder_cvbs.c b/drivers/gpu/drm/meson/meson_encoder_cvbs.c
index d1191de855d9..ddca22c8c1ff 100644
--- a/drivers/gpu/drm/meson/meson_encoder_cvbs.c
+++ b/drivers/gpu/drm/meson/meson_encoder_cvbs.c
@@ -104,7 +104,7 @@ static int meson_encoder_cvbs_get_modes(struct drm_bridge *bridge,
 	for (i = 0; i < MESON_CVBS_MODES_COUNT; ++i) {
 		struct meson_cvbs_mode *meson_mode = &meson_cvbs_modes[i];
 
-		mode = drm_mode_duplicate(priv->drm, &meson_mode->mode);
+		mode = drm_mode_duplicate(&priv->drm, &meson_mode->mode);
 		if (!mode) {
 			dev_err(priv->dev, "Failed to create a new display mode\n");
 			return 0;
@@ -221,7 +221,7 @@ static const struct drm_bridge_funcs meson_encoder_cvbs_bridge_funcs = {
 
 int meson_encoder_cvbs_probe(struct meson_drm *priv)
 {
-	struct drm_device *drm = priv->drm;
+	struct drm_device *drm = &priv->drm;
 	struct meson_encoder_cvbs *meson_encoder_cvbs;
 	struct drm_connector *connector;
 	struct device_node *remote;
@@ -256,7 +256,7 @@ int meson_encoder_cvbs_probe(struct meson_drm *priv)
 	meson_encoder_cvbs->priv = priv;
 
 	/* Encoder */
-	ret = drm_simple_encoder_init(priv->drm, &meson_encoder_cvbs->encoder,
+	ret = drm_simple_encoder_init(&priv->drm, &meson_encoder_cvbs->encoder,
 				      DRM_MODE_ENCODER_TVDAC);
 	if (ret)
 		return dev_err_probe(priv->dev, ret,
@@ -273,7 +273,7 @@ int meson_encoder_cvbs_probe(struct meson_drm *priv)
 	}
 
 	/* Initialize & attach Bridge Connector */
-	connector = drm_bridge_connector_init(priv->drm, &meson_encoder_cvbs->encoder);
+	connector = drm_bridge_connector_init(&priv->drm, &meson_encoder_cvbs->encoder);
 	if (IS_ERR(connector))
 		return dev_err_probe(priv->dev, PTR_ERR(connector),
 				     "Unable to create CVBS bridge connector\n");
diff --git a/drivers/gpu/drm/meson/meson_overlay.c b/drivers/gpu/drm/meson/meson_overlay.c
index 7f98de38842b..60ee7f758723 100644
--- a/drivers/gpu/drm/meson/meson_overlay.c
+++ b/drivers/gpu/drm/meson/meson_overlay.c
@@ -484,7 +484,7 @@ static void meson_overlay_atomic_update(struct drm_plane *plane,
 
 	interlace_mode = new_state->crtc->mode.flags & DRM_MODE_FLAG_INTERLACE;
 
-	spin_lock_irqsave(&priv->drm->event_lock, flags);
+	spin_lock_irqsave(&priv->drm.event_lock, flags);
 
 	if ((fb->modifier & DRM_FORMAT_MOD_AMLOGIC_FBC(0, 0)) ==
 			    DRM_FORMAT_MOD_AMLOGIC_FBC(0, 0)) {
@@ -717,7 +717,7 @@ static void meson_overlay_atomic_update(struct drm_plane *plane,
 
 	priv->viu.vd1_enabled = true;
 
-	spin_unlock_irqrestore(&priv->drm->event_lock, flags);
+	spin_unlock_irqrestore(&priv->drm.event_lock, flags);
 
 	DRM_DEBUG_DRIVER("\n");
 }
@@ -838,7 +838,7 @@ int meson_overlay_create(struct meson_drm *priv)
 
 	DRM_DEBUG_DRIVER("\n");
 
-	meson_overlay = devm_kzalloc(priv->drm->dev, sizeof(*meson_overlay),
+	meson_overlay = devm_kzalloc(priv->drm.dev, sizeof(*meson_overlay),
 				   GFP_KERNEL);
 	if (!meson_overlay)
 		return -ENOMEM;
@@ -846,7 +846,7 @@ int meson_overlay_create(struct meson_drm *priv)
 	meson_overlay->priv = priv;
 	plane = &meson_overlay->base;
 
-	drm_universal_plane_init(priv->drm, plane, 0xFF,
+	drm_universal_plane_init(&priv->drm, plane, 0xFF,
 				 &meson_overlay_funcs,
 				 supported_drm_formats,
 				 ARRAY_SIZE(supported_drm_formats),
diff --git a/drivers/gpu/drm/meson/meson_plane.c b/drivers/gpu/drm/meson/meson_plane.c
index b43ac61201f3..13be94309bf4 100644
--- a/drivers/gpu/drm/meson/meson_plane.c
+++ b/drivers/gpu/drm/meson/meson_plane.c
@@ -157,7 +157,7 @@ static void meson_plane_atomic_update(struct drm_plane *plane,
 	 * Update Buffer
 	 * Enable Plane
 	 */
-	spin_lock_irqsave(&priv->drm->event_lock, flags);
+	spin_lock_irqsave(&priv->drm.event_lock, flags);
 
 	/* Check if AFBC decoder is required for this buffer */
 	if ((meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM) ||
@@ -393,7 +393,7 @@ static void meson_plane_atomic_update(struct drm_plane *plane,
 
 	priv->viu.osd1_enabled = true;
 
-	spin_unlock_irqrestore(&priv->drm->event_lock, flags);
+	spin_unlock_irqrestore(&priv->drm.event_lock, flags);
 }
 
 static void meson_plane_atomic_disable(struct drm_plane *plane,
@@ -536,7 +536,7 @@ int meson_plane_create(struct meson_drm *priv)
 	const uint64_t *format_modifiers = format_modifiers_default;
 	int ret;
 
-	meson_plane = devm_kzalloc(priv->drm->dev, sizeof(*meson_plane),
+	meson_plane = devm_kzalloc(priv->drm.dev, sizeof(*meson_plane),
 				   GFP_KERNEL);
 	if (!meson_plane)
 		return -ENOMEM;
@@ -549,14 +549,14 @@ int meson_plane_create(struct meson_drm *priv)
 	else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A))
 		format_modifiers = format_modifiers_afbc_g12a;
 
-	ret = drm_universal_plane_init(priv->drm, plane, 0xFF,
+	ret = drm_universal_plane_init(&priv->drm, plane, 0xFF,
 					&meson_plane_funcs,
 					supported_drm_formats,
 					ARRAY_SIZE(supported_drm_formats),
 					format_modifiers,
 					DRM_PLANE_TYPE_PRIMARY, "meson_primary_plane");
 	if (ret) {
-		devm_kfree(priv->drm->dev, meson_plane);
+		devm_kfree(priv->drm.dev, meson_plane);
 		return ret;
 	}
 
-- 
2.30.2
Re: [PATCH v2] drm/meson: switch to a managed drm device
Posted by Martin Blumenstingl 1 year, 2 months ago
Hi Anastasia,

thank you for picking this up and apologies for my late reply.

On Tue, Sep 10, 2024 at 5:17 PM Anastasia Belova <abelova@astralinux.ru> wrote:
[...]
> @@ -215,7 +210,7 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
>         regs = devm_platform_ioremap_resource_byname(pdev, "vpu");
>         if (IS_ERR(regs)) {
>                 ret = PTR_ERR(regs);
> -               goto free_drm;
> +               goto remove_encoders;
can't we just return PTR_ERR(regs) here since all resources above are
now automatically free (as they are devm_* managed)?

>         }
>
>         priv->io_base = regs;
> @@ -223,13 +218,13 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
>         res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "hhi");
>         if (!res) {
>                 ret = -EINVAL;
> -               goto free_drm;
> +               goto remove_encoders;
same here, can't we just return -EINVAL directly?

>         }
>         /* Simply ioremap since it may be a shared register zone */
>         regs = devm_ioremap(dev, res->start, resource_size(res));
>         if (!regs) {
>                 ret = -EADDRNOTAVAIL;
> -               goto free_drm;
> +               goto remove_encoders;
also just return -EADDRNOTAVAIL directly

>         }
>
>         priv->hhi = devm_regmap_init_mmio(dev, regs,
> @@ -237,18 +232,18 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
>         if (IS_ERR(priv->hhi)) {
>                 dev_err(&pdev->dev, "Couldn't create the HHI regmap\n");
>                 ret = PTR_ERR(priv->hhi);
either return PTR_ERR(priv->hhi) here or convert the dev_err to
dev_err_probe and return it's value

> -               goto free_drm;
> +               goto remove_encoders;
>         }
>
>         priv->canvas = meson_canvas_get(dev);
>         if (IS_ERR(priv->canvas)) {
>                 ret = PTR_ERR(priv->canvas);
> -               goto free_drm;
> +               goto remove_encoders;
return PTR_ERR(priv->canvas);

>         }
>
>         ret = meson_canvas_alloc(priv->canvas, &priv->canvas_id_osd1);
>         if (ret)
> -               goto free_drm;
> +               goto remove_encoders;
meson_canvas_alloc() is the first non devm_* managed allocation.
so this is the last time we can simply "return ret;", starting with
the next error case we need goto for cleaning up resources.

>         ret = meson_canvas_alloc(priv->canvas, &priv->canvas_id_vd1_0);
>         if (ret)
>                 goto free_canvas_osd1;
(starting from here the goto free_... is needed and this one is
actually already correct)

> @@ -261,7 +256,7 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
>
>         priv->vsync_irq = platform_get_irq(pdev, 0);
>
> -       ret = drm_vblank_init(drm, 1);
> +       ret = drm_vblank_init(&priv->drm, 1);
>         if (ret)
>                 goto free_canvas_vd1_2;
>
> @@ -284,10 +279,10 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
>         ret = drmm_mode_config_init(drm);
>         if (ret)
>                 goto free_canvas_vd1_2;
> -       drm->mode_config.max_width = 3840;
> -       drm->mode_config.max_height = 2160;
> -       drm->mode_config.funcs = &meson_mode_config_funcs;
> -       drm->mode_config.helper_private = &meson_mode_config_helpers;
> +       priv->drm.mode_config.max_width = 3840;
> +       priv->drm.mode_config.max_height = 2160;
> +       priv->drm.mode_config.funcs = &meson_mode_config_funcs;
> +       priv->drm.mode_config.helper_private = &meson_mode_config_helpers;
>
>         /* Hardware Initialization */
>
> @@ -308,9 +303,9 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
>                 goto exit_afbcd;
>
>         if (has_components) {
> -               ret = component_bind_all(dev, drm);
> +               ret = component_bind_all(dev, &priv->drm);
>                 if (ret) {
> -                       dev_err(drm->dev, "Couldn't bind all components\n");
> +                       dev_err(priv->drm.dev, "Couldn't bind all components\n");
>                         /* Do not try to unbind */
>                         has_components = false;
>                         goto exit_afbcd;
just below this we have:
    ret = meson_encoder_hdmi_probe(priv);
    if (ret)
        goto exit_afbcd;
I think this is the place where we need to call component_unbind_all,
so we need some kind of "goto unbind_components;" here.
All other "goto exit_afbcd;" below will need to be converted to "goto
unbind_components;" (or whichever name you choose) as well.

Also the ordering where component_unbind_all() is incorrect. It's been
incorrect even before your patch - but maybe now is the right time to
clean it up?

I had to double check because I was surprised about the calls to
meson_encoder_{cvbs,dsi,hdmi}_remove(priv);
It turns out that it's safe to call these three functions at any time
because they only ever do something if their _probe() counterpart has
been called.



Best regards,
Martin
[PATCH v3] drm/meson: switch to a managed drm device
Posted by Anastasia Belova 1 year, 2 months ago
Switch to a managed drm device to cleanup some error handling
and make future work easier.

Fix dereference of NULL in meson_drv_bind_master by removing
drm_dev_put(drm) before meson_encoder_*_remove and
component_unbind_all where drm is dereferenced.

Co-developed by Linux Verification Center (linuxtesting.org).

Cc: stable@vger.kernel.org # 6.5
Fixes: 6a044642988b ("drm/meson: fix unbind path if HDMI fails to bind")
Signed-off-by: Anastasia Belova <abelova@astralinux.ru>
---
 drivers/gpu/drm/meson/meson_crtc.c         | 10 +--
 drivers/gpu/drm/meson/meson_drv.c          | 93 ++++++++++------------
 drivers/gpu/drm/meson/meson_drv.h          |  2 +-
 drivers/gpu/drm/meson/meson_encoder_cvbs.c |  8 +-
 drivers/gpu/drm/meson/meson_overlay.c      |  8 +-
 drivers/gpu/drm/meson/meson_plane.c        | 10 +--
 6 files changed, 59 insertions(+), 72 deletions(-)

diff --git a/drivers/gpu/drm/meson/meson_crtc.c b/drivers/gpu/drm/meson/meson_crtc.c
index d70616da8ce2..e1c0bf3baeea 100644
--- a/drivers/gpu/drm/meson/meson_crtc.c
+++ b/drivers/gpu/drm/meson/meson_crtc.c
@@ -662,13 +662,13 @@ void meson_crtc_irq(struct meson_drm *priv)
 
 	drm_crtc_handle_vblank(priv->crtc);
 
-	spin_lock_irqsave(&priv->drm->event_lock, flags);
+	spin_lock_irqsave(&priv->drm.event_lock, flags);
 	if (meson_crtc->event) {
 		drm_crtc_send_vblank_event(priv->crtc, meson_crtc->event);
 		drm_crtc_vblank_put(priv->crtc);
 		meson_crtc->event = NULL;
 	}
-	spin_unlock_irqrestore(&priv->drm->event_lock, flags);
+	spin_unlock_irqrestore(&priv->drm.event_lock, flags);
 }
 
 int meson_crtc_create(struct meson_drm *priv)
@@ -677,18 +677,18 @@ int meson_crtc_create(struct meson_drm *priv)
 	struct drm_crtc *crtc;
 	int ret;
 
-	meson_crtc = devm_kzalloc(priv->drm->dev, sizeof(*meson_crtc),
+	meson_crtc = devm_kzalloc(priv->drm.dev, sizeof(*meson_crtc),
 				  GFP_KERNEL);
 	if (!meson_crtc)
 		return -ENOMEM;
 
 	meson_crtc->priv = priv;
 	crtc = &meson_crtc->base;
-	ret = drm_crtc_init_with_planes(priv->drm, crtc,
+	ret = drm_crtc_init_with_planes(&priv->drm, crtc,
 					priv->primary_plane, NULL,
 					&meson_crtc_funcs, "meson_crtc");
 	if (ret) {
-		dev_err(priv->drm->dev, "Failed to init CRTC\n");
+		dev_err(priv->drm.dev, "Failed to init CRTC\n");
 		return ret;
 	}
 
diff --git a/drivers/gpu/drm/meson/meson_drv.c b/drivers/gpu/drm/meson/meson_drv.c
index 4bd0baa2a4f5..dd87c6b61e9e 100644
--- a/drivers/gpu/drm/meson/meson_drv.c
+++ b/drivers/gpu/drm/meson/meson_drv.c
@@ -182,7 +182,6 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
 	struct platform_device *pdev = to_platform_device(dev);
 	const struct meson_drm_match_data *match;
 	struct meson_drm *priv;
-	struct drm_device *drm;
 	struct resource *res;
 	void __iomem *regs;
 	int ret, i;
@@ -197,58 +196,49 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
 	if (!match)
 		return -ENODEV;
 
-	drm = drm_dev_alloc(&meson_driver, dev);
-	if (IS_ERR(drm))
-		return PTR_ERR(drm);
+	priv = devm_drm_dev_alloc(dev, &meson_driver,
+				 struct meson_drm, drm);
 
-	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
-	if (!priv) {
-		ret = -ENOMEM;
-		goto free_drm;
-	}
-	drm->dev_private = priv;
-	priv->drm = drm;
+	if (IS_ERR(priv))
+		return PTR_ERR(priv);
+
+	priv->drm.dev_private = priv;
 	priv->dev = dev;
 	priv->compat = match->compat;
 	priv->afbcd.ops = match->afbcd_ops;
 
 	regs = devm_platform_ioremap_resource_byname(pdev, "vpu");
 	if (IS_ERR(regs)) {
-		ret = PTR_ERR(regs);
-		goto free_drm;
+		return PTR_ERR(regs);
 	}
 
 	priv->io_base = regs;
 
 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "hhi");
 	if (!res) {
-		ret = -EINVAL;
-		goto free_drm;
+		return -EINVAL;
 	}
 	/* Simply ioremap since it may be a shared register zone */
 	regs = devm_ioremap(dev, res->start, resource_size(res));
 	if (!regs) {
-		ret = -EADDRNOTAVAIL;
-		goto free_drm;
+		return -EADDRNOTAVAIL;
 	}
 
 	priv->hhi = devm_regmap_init_mmio(dev, regs,
 					  &meson_regmap_config);
 	if (IS_ERR(priv->hhi)) {
 		dev_err(&pdev->dev, "Couldn't create the HHI regmap\n");
-		ret = PTR_ERR(priv->hhi);
-		goto free_drm;
+		return PTR_ERR(priv->hhi);
 	}
 
 	priv->canvas = meson_canvas_get(dev);
 	if (IS_ERR(priv->canvas)) {
-		ret = PTR_ERR(priv->canvas);
-		goto free_drm;
+		return PTR_ERR(priv->canvas);
 	}
 
 	ret = meson_canvas_alloc(priv->canvas, &priv->canvas_id_osd1);
 	if (ret)
-		goto free_drm;
+		return ret;
 	ret = meson_canvas_alloc(priv->canvas, &priv->canvas_id_vd1_0);
 	if (ret)
 		goto free_canvas_osd1;
@@ -261,7 +251,7 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
 
 	priv->vsync_irq = platform_get_irq(pdev, 0);
 
-	ret = drm_vblank_init(drm, 1);
+	ret = drm_vblank_init(&priv->drm, 1);
 	if (ret)
 		goto free_canvas_vd1_2;
 
@@ -281,13 +271,13 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
 	if (ret)
 		goto free_canvas_vd1_2;
 
-	ret = drmm_mode_config_init(drm);
+	ret = drmm_mode_config_init(&priv->drm);
 	if (ret)
 		goto free_canvas_vd1_2;
-	drm->mode_config.max_width = 3840;
-	drm->mode_config.max_height = 2160;
-	drm->mode_config.funcs = &meson_mode_config_funcs;
-	drm->mode_config.helper_private	= &meson_mode_config_helpers;
+	priv->drm.mode_config.max_width = 3840;
+	priv->drm.mode_config.max_height = 2160;
+	priv->drm.mode_config.funcs = &meson_mode_config_funcs;
+	priv->drm.mode_config.helper_private = &meson_mode_config_helpers;
 
 	/* Hardware Initialization */
 
@@ -308,9 +298,9 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
 		goto exit_afbcd;
 
 	if (has_components) {
-		ret = component_bind_all(dev, drm);
+		ret = component_bind_all(dev, &priv->drm);
 		if (ret) {
-			dev_err(drm->dev, "Couldn't bind all components\n");
+			dev_err(priv->drm.dev, "Couldn't bind all components\n");
 			/* Do not try to unbind */
 			has_components = false;
 			goto exit_afbcd;
@@ -319,46 +309,49 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
 
 	ret = meson_encoder_hdmi_probe(priv);
 	if (ret)
-		goto exit_afbcd;
+		goto unbind_components;
 
 	if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) {
 		ret = meson_encoder_dsi_probe(priv);
 		if (ret)
-			goto exit_afbcd;
+			goto unbind_components;
 	}
 
 	ret = meson_plane_create(priv);
 	if (ret)
-		goto exit_afbcd;
+		goto unbind_components;
 
 	ret = meson_overlay_create(priv);
 	if (ret)
-		goto exit_afbcd;
+		goto unbind_components;
 
 	ret = meson_crtc_create(priv);
 	if (ret)
-		goto exit_afbcd;
+		goto unbind_components;
 
-	ret = request_irq(priv->vsync_irq, meson_irq, 0, drm->driver->name, drm);
+	ret = request_irq(priv->vsync_irq, meson_irq, 0, priv->drm.driver->name, &priv->drm);
 	if (ret)
-		goto exit_afbcd;
+		goto unbind_components;
 
-	drm_mode_config_reset(drm);
+	drm_mode_config_reset(&priv->drm);
 
-	drm_kms_helper_poll_init(drm);
+	drm_kms_helper_poll_init(&priv->drm);
 
 	platform_set_drvdata(pdev, priv);
 
-	ret = drm_dev_register(drm, 0);
+	ret = drm_dev_register(&priv->drm, 0);
 	if (ret)
 		goto uninstall_irq;
 
-	drm_fbdev_dma_setup(drm, 32);
+	drm_fbdev_dma_setup(&priv->drm, 32);
 
 	return 0;
 
 uninstall_irq:
-	free_irq(priv->vsync_irq, drm);
+	free_irq(priv->vsync_irq, &priv->drm);
+unbind_components:
+	if (has_components)
+		component_unbind_all(dev, &priv->drm);
 exit_afbcd:
 	if (priv->afbcd.ops)
 		priv->afbcd.ops->exit(priv);
@@ -370,16 +363,11 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
 	meson_canvas_free(priv->canvas, priv->canvas_id_vd1_0);
 free_canvas_osd1:
 	meson_canvas_free(priv->canvas, priv->canvas_id_osd1);
-free_drm:
-	drm_dev_put(drm);
 
 	meson_encoder_dsi_remove(priv);
 	meson_encoder_hdmi_remove(priv);
 	meson_encoder_cvbs_remove(priv);
 
-	if (has_components)
-		component_unbind_all(dev, drm);
-
 	return ret;
 }
 
@@ -391,7 +379,7 @@ static int meson_drv_bind(struct device *dev)
 static void meson_drv_unbind(struct device *dev)
 {
 	struct meson_drm *priv = dev_get_drvdata(dev);
-	struct drm_device *drm = priv->drm;
+	struct drm_device *drm = &priv->drm;
 
 	if (priv->canvas) {
 		meson_canvas_free(priv->canvas, priv->canvas_id_osd1);
@@ -404,7 +392,6 @@ static void meson_drv_unbind(struct device *dev)
 	drm_kms_helper_poll_fini(drm);
 	drm_atomic_helper_shutdown(drm);
 	free_irq(priv->vsync_irq, drm);
-	drm_dev_put(drm);
 
 	meson_encoder_dsi_remove(priv);
 	meson_encoder_hdmi_remove(priv);
@@ -428,7 +415,7 @@ static int __maybe_unused meson_drv_pm_suspend(struct device *dev)
 	if (!priv)
 		return 0;
 
-	return drm_mode_config_helper_suspend(priv->drm);
+	return drm_mode_config_helper_suspend(&priv->drm);
 }
 
 static int __maybe_unused meson_drv_pm_resume(struct device *dev)
@@ -445,7 +432,7 @@ static int __maybe_unused meson_drv_pm_resume(struct device *dev)
 	if (priv->afbcd.ops)
 		priv->afbcd.ops->init(priv);
 
-	return drm_mode_config_helper_resume(priv->drm);
+	return drm_mode_config_helper_resume(&priv->drm);
 }
 
 static void meson_drv_shutdown(struct platform_device *pdev)
@@ -455,8 +442,8 @@ static void meson_drv_shutdown(struct platform_device *pdev)
 	if (!priv)
 		return;
 
-	drm_kms_helper_poll_fini(priv->drm);
-	drm_atomic_helper_shutdown(priv->drm);
+	drm_kms_helper_poll_fini(&priv->drm);
+	drm_atomic_helper_shutdown(&priv->drm);
 }
 
 /*
diff --git a/drivers/gpu/drm/meson/meson_drv.h b/drivers/gpu/drm/meson/meson_drv.h
index 3f9345c14f31..c4c6c810cb20 100644
--- a/drivers/gpu/drm/meson/meson_drv.h
+++ b/drivers/gpu/drm/meson/meson_drv.h
@@ -53,7 +53,7 @@ struct meson_drm {
 	u8 canvas_id_vd1_1;
 	u8 canvas_id_vd1_2;
 
-	struct drm_device *drm;
+	struct drm_device drm;
 	struct drm_crtc *crtc;
 	struct drm_plane *primary_plane;
 	struct drm_plane *overlay_plane;
diff --git a/drivers/gpu/drm/meson/meson_encoder_cvbs.c b/drivers/gpu/drm/meson/meson_encoder_cvbs.c
index d1191de855d9..ddca22c8c1ff 100644
--- a/drivers/gpu/drm/meson/meson_encoder_cvbs.c
+++ b/drivers/gpu/drm/meson/meson_encoder_cvbs.c
@@ -104,7 +104,7 @@ static int meson_encoder_cvbs_get_modes(struct drm_bridge *bridge,
 	for (i = 0; i < MESON_CVBS_MODES_COUNT; ++i) {
 		struct meson_cvbs_mode *meson_mode = &meson_cvbs_modes[i];
 
-		mode = drm_mode_duplicate(priv->drm, &meson_mode->mode);
+		mode = drm_mode_duplicate(&priv->drm, &meson_mode->mode);
 		if (!mode) {
 			dev_err(priv->dev, "Failed to create a new display mode\n");
 			return 0;
@@ -221,7 +221,7 @@ static const struct drm_bridge_funcs meson_encoder_cvbs_bridge_funcs = {
 
 int meson_encoder_cvbs_probe(struct meson_drm *priv)
 {
-	struct drm_device *drm = priv->drm;
+	struct drm_device *drm = &priv->drm;
 	struct meson_encoder_cvbs *meson_encoder_cvbs;
 	struct drm_connector *connector;
 	struct device_node *remote;
@@ -256,7 +256,7 @@ int meson_encoder_cvbs_probe(struct meson_drm *priv)
 	meson_encoder_cvbs->priv = priv;
 
 	/* Encoder */
-	ret = drm_simple_encoder_init(priv->drm, &meson_encoder_cvbs->encoder,
+	ret = drm_simple_encoder_init(&priv->drm, &meson_encoder_cvbs->encoder,
 				      DRM_MODE_ENCODER_TVDAC);
 	if (ret)
 		return dev_err_probe(priv->dev, ret,
@@ -273,7 +273,7 @@ int meson_encoder_cvbs_probe(struct meson_drm *priv)
 	}
 
 	/* Initialize & attach Bridge Connector */
-	connector = drm_bridge_connector_init(priv->drm, &meson_encoder_cvbs->encoder);
+	connector = drm_bridge_connector_init(&priv->drm, &meson_encoder_cvbs->encoder);
 	if (IS_ERR(connector))
 		return dev_err_probe(priv->dev, PTR_ERR(connector),
 				     "Unable to create CVBS bridge connector\n");
diff --git a/drivers/gpu/drm/meson/meson_overlay.c b/drivers/gpu/drm/meson/meson_overlay.c
index 7f98de38842b..60ee7f758723 100644
--- a/drivers/gpu/drm/meson/meson_overlay.c
+++ b/drivers/gpu/drm/meson/meson_overlay.c
@@ -484,7 +484,7 @@ static void meson_overlay_atomic_update(struct drm_plane *plane,
 
 	interlace_mode = new_state->crtc->mode.flags & DRM_MODE_FLAG_INTERLACE;
 
-	spin_lock_irqsave(&priv->drm->event_lock, flags);
+	spin_lock_irqsave(&priv->drm.event_lock, flags);
 
 	if ((fb->modifier & DRM_FORMAT_MOD_AMLOGIC_FBC(0, 0)) ==
 			    DRM_FORMAT_MOD_AMLOGIC_FBC(0, 0)) {
@@ -717,7 +717,7 @@ static void meson_overlay_atomic_update(struct drm_plane *plane,
 
 	priv->viu.vd1_enabled = true;
 
-	spin_unlock_irqrestore(&priv->drm->event_lock, flags);
+	spin_unlock_irqrestore(&priv->drm.event_lock, flags);
 
 	DRM_DEBUG_DRIVER("\n");
 }
@@ -838,7 +838,7 @@ int meson_overlay_create(struct meson_drm *priv)
 
 	DRM_DEBUG_DRIVER("\n");
 
-	meson_overlay = devm_kzalloc(priv->drm->dev, sizeof(*meson_overlay),
+	meson_overlay = devm_kzalloc(priv->drm.dev, sizeof(*meson_overlay),
 				   GFP_KERNEL);
 	if (!meson_overlay)
 		return -ENOMEM;
@@ -846,7 +846,7 @@ int meson_overlay_create(struct meson_drm *priv)
 	meson_overlay->priv = priv;
 	plane = &meson_overlay->base;
 
-	drm_universal_plane_init(priv->drm, plane, 0xFF,
+	drm_universal_plane_init(&priv->drm, plane, 0xFF,
 				 &meson_overlay_funcs,
 				 supported_drm_formats,
 				 ARRAY_SIZE(supported_drm_formats),
diff --git a/drivers/gpu/drm/meson/meson_plane.c b/drivers/gpu/drm/meson/meson_plane.c
index b43ac61201f3..13be94309bf4 100644
--- a/drivers/gpu/drm/meson/meson_plane.c
+++ b/drivers/gpu/drm/meson/meson_plane.c
@@ -157,7 +157,7 @@ static void meson_plane_atomic_update(struct drm_plane *plane,
 	 * Update Buffer
 	 * Enable Plane
 	 */
-	spin_lock_irqsave(&priv->drm->event_lock, flags);
+	spin_lock_irqsave(&priv->drm.event_lock, flags);
 
 	/* Check if AFBC decoder is required for this buffer */
 	if ((meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM) ||
@@ -393,7 +393,7 @@ static void meson_plane_atomic_update(struct drm_plane *plane,
 
 	priv->viu.osd1_enabled = true;
 
-	spin_unlock_irqrestore(&priv->drm->event_lock, flags);
+	spin_unlock_irqrestore(&priv->drm.event_lock, flags);
 }
 
 static void meson_plane_atomic_disable(struct drm_plane *plane,
@@ -536,7 +536,7 @@ int meson_plane_create(struct meson_drm *priv)
 	const uint64_t *format_modifiers = format_modifiers_default;
 	int ret;
 
-	meson_plane = devm_kzalloc(priv->drm->dev, sizeof(*meson_plane),
+	meson_plane = devm_kzalloc(priv->drm.dev, sizeof(*meson_plane),
 				   GFP_KERNEL);
 	if (!meson_plane)
 		return -ENOMEM;
@@ -549,14 +549,14 @@ int meson_plane_create(struct meson_drm *priv)
 	else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A))
 		format_modifiers = format_modifiers_afbc_g12a;
 
-	ret = drm_universal_plane_init(priv->drm, plane, 0xFF,
+	ret = drm_universal_plane_init(&priv->drm, plane, 0xFF,
 					&meson_plane_funcs,
 					supported_drm_formats,
 					ARRAY_SIZE(supported_drm_formats),
 					format_modifiers,
 					DRM_PLANE_TYPE_PRIMARY, "meson_primary_plane");
 	if (ret) {
-		devm_kfree(priv->drm->dev, meson_plane);
+		devm_kfree(priv->drm.dev, meson_plane);
 		return ret;
 	}
 
-- 
2.30.2
Re: [PATCH v3] drm/meson: switch to a managed drm device
Posted by kernel test robot 1 year, 2 months ago
Hi Anastasia,

kernel test robot noticed the following build errors:

[auto build test ERROR on linus/master]
[also build test ERROR on v6.12-rc1 next-20240930]
[cannot apply to drm-misc/drm-misc-next]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Anastasia-Belova/drm-meson-switch-to-a-managed-drm-device/20240930-162755
base:   linus/master
patch link:    https://lore.kernel.org/r/20240930082640.129543-1-abelova%40astralinux.ru
patch subject: [PATCH v3] drm/meson: switch to a managed drm device
config: arm64-defconfig (https://download.01.org/0day-ci/archive/20241001/202410011034.NTOKwoXq-lkp@intel.com/config)
compiler: aarch64-linux-gcc (GCC) 14.1.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20241001/202410011034.NTOKwoXq-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202410011034.NTOKwoXq-lkp@intel.com/

All errors (new ones prefixed by >>):

   In file included from drivers/gpu/drm/meson/meson_viu.c:14:
>> drivers/gpu/drm/meson/meson_drv.h:56:27: error: field 'drm' has incomplete type
      56 |         struct drm_device drm;
         |                           ^~~
--
   drivers/gpu/drm/meson/meson_encoder_hdmi.c: In function 'meson_encoder_hdmi_probe':
>> drivers/gpu/drm/meson/meson_encoder_hdmi.c:405:43: error: incompatible type for argument 1 of 'drm_simple_encoder_init'
     405 |         ret = drm_simple_encoder_init(priv->drm, &meson_encoder_hdmi->encoder,
         |                                       ~~~~^~~~~
         |                                           |
         |                                           struct drm_device
   In file included from drivers/gpu/drm/meson/meson_encoder_hdmi.c:27:
   include/drm/drm_simple_kms_helper.h:261:48: note: expected 'struct drm_device *' but argument is of type 'struct drm_device'
     261 | int drm_simple_encoder_init(struct drm_device *dev,
         |                             ~~~~~~~~~~~~~~~~~~~^~~
>> drivers/gpu/drm/meson/meson_encoder_hdmi.c:423:71: error: incompatible type for argument 1 of 'drm_bridge_connector_init'
     423 |         meson_encoder_hdmi->connector = drm_bridge_connector_init(priv->drm,
         |                                                                   ~~~~^~~~~
         |                                                                       |
         |                                                                       struct drm_device
   In file included from drivers/gpu/drm/meson/meson_encoder_hdmi.c:23:
   include/drm/drm_bridge_connector.h:13:68: note: expected 'struct drm_device *' but argument is of type 'struct drm_device'
      13 | struct drm_connector *drm_bridge_connector_init(struct drm_device *drm,
         |                                                 ~~~~~~~~~~~~~~~~~~~^~~
--
   drivers/gpu/drm/meson/meson_encoder_dsi.c: In function 'meson_encoder_dsi_probe':
>> drivers/gpu/drm/meson/meson_encoder_dsi.c:135:43: error: incompatible type for argument 1 of 'drm_simple_encoder_init'
     135 |         ret = drm_simple_encoder_init(priv->drm, &meson_encoder_dsi->encoder,
         |                                       ~~~~^~~~~
         |                                           |
         |                                           struct drm_device
   In file included from drivers/gpu/drm/meson/meson_encoder_dsi.c:13:
   include/drm/drm_simple_kms_helper.h:261:48: note: expected 'struct drm_device *' but argument is of type 'struct drm_device'
     261 | int drm_simple_encoder_init(struct drm_device *dev,
         |                             ~~~~~~~~~~~~~~~~~~~^~~


vim +/drm +56 drivers/gpu/drm/meson/meson_drv.h

    42	
    43	struct meson_drm {
    44		struct device *dev;
    45		enum vpu_compatible compat;
    46		void __iomem *io_base;
    47		struct regmap *hhi;
    48		int vsync_irq;
    49	
    50		struct meson_canvas *canvas;
    51		u8 canvas_id_osd1;
    52		u8 canvas_id_vd1_0;
    53		u8 canvas_id_vd1_1;
    54		u8 canvas_id_vd1_2;
    55	
  > 56		struct drm_device drm;
    57		struct drm_crtc *crtc;
    58		struct drm_plane *primary_plane;
    59		struct drm_plane *overlay_plane;
    60		void *encoders[MESON_ENC_LAST];
    61	
    62		const struct meson_drm_soc_limits *limits;
    63	
    64		/* Components Data */
    65		struct {
    66			bool osd1_enabled;
    67			bool osd1_interlace;
    68			bool osd1_commit;
    69			bool osd1_afbcd;
    70			uint32_t osd1_ctrl_stat;
    71			uint32_t osd1_ctrl_stat2;
    72			uint32_t osd1_blk0_cfg[5];
    73			uint32_t osd1_blk1_cfg4;
    74			uint32_t osd1_blk2_cfg4;
    75			uint32_t osd1_addr;
    76			uint32_t osd1_stride;
    77			uint32_t osd1_height;
    78			uint32_t osd1_width;
    79			uint32_t osd_sc_ctrl0;
    80			uint32_t osd_sc_i_wh_m1;
    81			uint32_t osd_sc_o_h_start_end;
    82			uint32_t osd_sc_o_v_start_end;
    83			uint32_t osd_sc_v_ini_phase;
    84			uint32_t osd_sc_v_phase_step;
    85			uint32_t osd_sc_h_ini_phase;
    86			uint32_t osd_sc_h_phase_step;
    87			uint32_t osd_sc_h_ctrl0;
    88			uint32_t osd_sc_v_ctrl0;
    89			uint32_t osd_blend_din0_scope_h;
    90			uint32_t osd_blend_din0_scope_v;
    91			uint32_t osb_blend0_size;
    92			uint32_t osb_blend1_size;
    93	
    94			bool vd1_enabled;
    95			bool vd1_commit;
    96			bool vd1_afbc;
    97			unsigned int vd1_planes;
    98			uint32_t vd1_if0_gen_reg;
    99			uint32_t vd1_if0_luma_x0;
   100			uint32_t vd1_if0_luma_y0;
   101			uint32_t vd1_if0_chroma_x0;
   102			uint32_t vd1_if0_chroma_y0;
   103			uint32_t vd1_if0_repeat_loop;
   104			uint32_t vd1_if0_luma0_rpt_pat;
   105			uint32_t vd1_if0_chroma0_rpt_pat;
   106			uint32_t vd1_range_map_y;
   107			uint32_t vd1_range_map_cb;
   108			uint32_t vd1_range_map_cr;
   109			uint32_t viu_vd1_fmt_w;
   110			uint32_t vd1_if0_canvas0;
   111			uint32_t vd1_if0_gen_reg2;
   112			uint32_t viu_vd1_fmt_ctrl;
   113			uint32_t vd1_addr0;
   114			uint32_t vd1_addr1;
   115			uint32_t vd1_addr2;
   116			uint32_t vd1_stride0;
   117			uint32_t vd1_stride1;
   118			uint32_t vd1_stride2;
   119			uint32_t vd1_height0;
   120			uint32_t vd1_height1;
   121			uint32_t vd1_height2;
   122			uint32_t vd1_afbc_mode;
   123			uint32_t vd1_afbc_en;
   124			uint32_t vd1_afbc_head_addr;
   125			uint32_t vd1_afbc_body_addr;
   126			uint32_t vd1_afbc_conv_ctrl;
   127			uint32_t vd1_afbc_dec_def_color;
   128			uint32_t vd1_afbc_vd_cfmt_ctrl;
   129			uint32_t vd1_afbc_vd_cfmt_w;
   130			uint32_t vd1_afbc_vd_cfmt_h;
   131			uint32_t vd1_afbc_mif_hor_scope;
   132			uint32_t vd1_afbc_mif_ver_scope;
   133			uint32_t vd1_afbc_size_out;
   134			uint32_t vd1_afbc_pixel_hor_scope;
   135			uint32_t vd1_afbc_pixel_ver_scope;
   136			uint32_t vd1_afbc_size_in;
   137			uint32_t vpp_pic_in_height;
   138			uint32_t vpp_postblend_vd1_h_start_end;
   139			uint32_t vpp_postblend_vd1_v_start_end;
   140			uint32_t vpp_hsc_region12_startp;
   141			uint32_t vpp_hsc_region34_startp;
   142			uint32_t vpp_hsc_region4_endp;
   143			uint32_t vpp_hsc_start_phase_step;
   144			uint32_t vpp_hsc_region1_phase_slope;
   145			uint32_t vpp_hsc_region3_phase_slope;
   146			uint32_t vpp_line_in_length;
   147			uint32_t vpp_preblend_h_size;
   148			uint32_t vpp_vsc_region12_startp;
   149			uint32_t vpp_vsc_region34_startp;
   150			uint32_t vpp_vsc_region4_endp;
   151			uint32_t vpp_vsc_start_phase_step;
   152			uint32_t vpp_vsc_ini_phase;
   153			uint32_t vpp_vsc_phase_ctrl;
   154			uint32_t vpp_hsc_phase_ctrl;
   155			uint32_t vpp_blend_vd2_h_start_end;
   156			uint32_t vpp_blend_vd2_v_start_end;
   157		} viu;
   158	
   159		struct {
   160			unsigned int current_mode;
   161			bool hdmi_repeat;
   162			bool venc_repeat;
   163			bool hdmi_use_enci;
   164		} venc;
   165	
   166		struct {
   167			dma_addr_t addr_dma;
   168			uint32_t *addr;
   169			unsigned int offset;
   170		} rdma;
   171	
   172		struct {
   173			struct meson_afbcd_ops *ops;
   174			u64 modifier;
   175			u32 format;
   176		} afbcd;
   177	};
   178	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
Re: [PATCH v3] drm/meson: switch to a managed drm device
Posted by kernel test robot 1 year, 2 months ago
Hi Anastasia,

kernel test robot noticed the following build errors:

[auto build test ERROR on linus/master]
[also build test ERROR on v6.12-rc1 next-20240930]
[cannot apply to drm-misc/drm-misc-next]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Anastasia-Belova/drm-meson-switch-to-a-managed-drm-device/20240930-162755
base:   linus/master
patch link:    https://lore.kernel.org/r/20240930082640.129543-1-abelova%40astralinux.ru
patch subject: [PATCH v3] drm/meson: switch to a managed drm device
config: arm-randconfig-001-20240930 (https://download.01.org/0day-ci/archive/20241001/202410010450.fOkIu1ki-lkp@intel.com/config)
compiler: clang version 15.0.7 (https://github.com/llvm/llvm-project 8dfdcc7b7bf66834a761bd8de445840ef68e4d1a)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20241001/202410010450.fOkIu1ki-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202410010450.fOkIu1ki-lkp@intel.com/

All errors (new ones prefixed by >>):

   In file included from drivers/gpu/drm/meson/meson_osd_afbcd.c:12:
>> drivers/gpu/drm/meson/meson_drv.h:56:20: error: field has incomplete type 'struct drm_device'
           struct drm_device drm;
                             ^
   include/drm/drm_print.h:37:8: note: forward declaration of 'struct drm_device'
   struct drm_device;
          ^
   1 error generated.
--
   In file included from drivers/gpu/drm/meson/meson_venc.c:14:
>> drivers/gpu/drm/meson/meson_drv.h:56:20: error: field has incomplete type 'struct drm_device'
           struct drm_device drm;
                             ^
   include/drm/drm_lease.h:12:8: note: forward declaration of 'struct drm_device'
   struct drm_device;
          ^
   1 error generated.
--
   In file included from drivers/gpu/drm/meson/meson_vclk.c:12:
>> drivers/gpu/drm/meson/meson_drv.h:56:20: error: field has incomplete type 'struct drm_device'
           struct drm_device drm;
                             ^
   include/drm/drm_print.h:37:8: note: forward declaration of 'struct drm_device'
   struct drm_device;
          ^
   In file included from drivers/gpu/drm/meson/meson_vclk.c:13:
   In file included from drivers/gpu/drm/meson/meson_vclk.h:12:
   In file included from include/drm/drm_modes.h:33:
   In file included from include/drm/drm_connector.h:32:
   In file included from include/drm/drm_util.h:36:
   In file included from include/linux/kgdb.h:19:
   In file included from include/linux/kprobes.h:28:
   In file included from include/linux/ftrace.h:13:
   In file included from include/linux/kallsyms.h:13:
   In file included from include/linux/mm.h:1120:
   In file included from include/linux/huge_mm.h:8:
   In file included from include/linux/fs.h:33:
   In file included from include/linux/percpu-rwsem.h:7:
   In file included from include/linux/rcuwait.h:6:
   In file included from include/linux/sched/signal.h:6:
   include/linux/signal.h:98:11: warning: array index 3 is past the end of the array (which contains 2 elements) [-Warray-bounds]
                   return (set->sig[3] | set->sig[2] |
                           ^        ~
   arch/arm/include/asm/signal.h:17:2: note: array 'sig' declared here
           unsigned long sig[_NSIG_WORDS];
           ^
   In file included from drivers/gpu/drm/meson/meson_vclk.c:13:
   In file included from drivers/gpu/drm/meson/meson_vclk.h:12:
   In file included from include/drm/drm_modes.h:33:
   In file included from include/drm/drm_connector.h:32:
   In file included from include/drm/drm_util.h:36:
   In file included from include/linux/kgdb.h:19:
   In file included from include/linux/kprobes.h:28:
   In file included from include/linux/ftrace.h:13:
   In file included from include/linux/kallsyms.h:13:
   In file included from include/linux/mm.h:1120:
   In file included from include/linux/huge_mm.h:8:
   In file included from include/linux/fs.h:33:
   In file included from include/linux/percpu-rwsem.h:7:
   In file included from include/linux/rcuwait.h:6:
   In file included from include/linux/sched/signal.h:6:
   include/linux/signal.h:98:25: warning: array index 2 is past the end of the array (which contains 2 elements) [-Warray-bounds]
                   return (set->sig[3] | set->sig[2] |
                                         ^        ~
   arch/arm/include/asm/signal.h:17:2: note: array 'sig' declared here
           unsigned long sig[_NSIG_WORDS];
           ^
   In file included from drivers/gpu/drm/meson/meson_vclk.c:13:
   In file included from drivers/gpu/drm/meson/meson_vclk.h:12:
   In file included from include/drm/drm_modes.h:33:
   In file included from include/drm/drm_connector.h:32:
   In file included from include/drm/drm_util.h:36:
   In file included from include/linux/kgdb.h:19:
   In file included from include/linux/kprobes.h:28:
   In file included from include/linux/ftrace.h:13:
   In file included from include/linux/kallsyms.h:13:
   In file included from include/linux/mm.h:1120:
   In file included from include/linux/huge_mm.h:8:
   In file included from include/linux/fs.h:33:
   In file included from include/linux/percpu-rwsem.h:7:
   In file included from include/linux/rcuwait.h:6:
   In file included from include/linux/sched/signal.h:6:
   include/linux/signal.h:114:11: warning: array index 3 is past the end of the array (which contains 2 elements) [-Warray-bounds]
                   return  (set1->sig[3] == set2->sig[3]) &&
                            ^         ~
   arch/arm/include/asm/signal.h:17:2: note: array 'sig' declared here
           unsigned long sig[_NSIG_WORDS];
           ^
   In file included from drivers/gpu/drm/meson/meson_vclk.c:13:
   In file included from drivers/gpu/drm/meson/meson_vclk.h:12:
   In file included from include/drm/drm_modes.h:33:
   In file included from include/drm/drm_connector.h:32:
   In file included from include/drm/drm_util.h:36:
   In file included from include/linux/kgdb.h:19:
   In file included from include/linux/kprobes.h:28:
   In file included from include/linux/ftrace.h:13:
   In file included from include/linux/kallsyms.h:13:
   In file included from include/linux/mm.h:1120:
   In file included from include/linux/huge_mm.h:8:
   In file included from include/linux/fs.h:33:
   In file included from include/linux/percpu-rwsem.h:7:
   In file included from include/linux/rcuwait.h:6:
   In file included from include/linux/sched/signal.h:6:
   include/linux/signal.h:114:27: warning: array index 3 is past the end of the array (which contains 2 elements) [-Warray-bounds]
                   return  (set1->sig[3] == set2->sig[3]) &&
                                            ^         ~
   arch/arm/include/asm/signal.h:17:2: note: array 'sig' declared here
           unsigned long sig[_NSIG_WORDS];
           ^
   In file included from drivers/gpu/drm/meson/meson_vclk.c:13:
   In file included from drivers/gpu/drm/meson/meson_vclk.h:12:
   In file included from include/drm/drm_modes.h:33:
   In file included from include/drm/drm_connector.h:32:
   In file included from include/drm/drm_util.h:36:
   In file included from include/linux/kgdb.h:19:
   In file included from include/linux/kprobes.h:28:
   In file included from include/linux/ftrace.h:13:
   In file included from include/linux/kallsyms.h:13:
   In file included from include/linux/mm.h:1120:
   In file included from include/linux/huge_mm.h:8:
--
   In file included from drivers/gpu/drm/meson/meson_vpp.c:11:
>> drivers/gpu/drm/meson/meson_drv.h:56:20: error: field has incomplete type 'struct drm_device'
           struct drm_device drm;
                             ^
   drivers/gpu/drm/meson/meson_drv.h:15:8: note: forward declaration of 'struct drm_device'
   struct drm_device;
          ^
   1 error generated.
--
>> drivers/gpu/drm/meson/meson_encoder_dsi.c:135:32: error: passing 'struct drm_device' to parameter of incompatible type 'struct drm_device *'; take the address with &
           ret = drm_simple_encoder_init(priv->drm, &meson_encoder_dsi->encoder,
                                         ^~~~~~~~~
                                         &
   include/drm/drm_simple_kms_helper.h:261:48: note: passing argument to parameter 'dev' here
   int drm_simple_encoder_init(struct drm_device *dev,
                                                  ^
   1 error generated.
--
   In file included from drivers/gpu/drm/meson/meson_viu.c:14:
>> drivers/gpu/drm/meson/meson_drv.h:56:20: error: field has incomplete type 'struct drm_device'
           struct drm_device drm;
                             ^
   include/drm/drm_fourcc.h:56:8: note: forward declaration of 'struct drm_device'
   struct drm_device;
          ^
   1 error generated.
--
>> drivers/gpu/drm/meson/meson_encoder_hdmi.c:405:32: error: passing 'struct drm_device' to parameter of incompatible type 'struct drm_device *'; take the address with &
           ret = drm_simple_encoder_init(priv->drm, &meson_encoder_hdmi->encoder,
                                         ^~~~~~~~~
                                         &
   include/drm/drm_simple_kms_helper.h:261:48: note: passing argument to parameter 'dev' here
   int drm_simple_encoder_init(struct drm_device *dev,
                                                  ^
   drivers/gpu/drm/meson/meson_encoder_hdmi.c:423:60: error: passing 'struct drm_device' to parameter of incompatible type 'struct drm_device *'; take the address with &
           meson_encoder_hdmi->connector = drm_bridge_connector_init(priv->drm,
                                                                     ^~~~~~~~~
                                                                     &
   include/drm/drm_bridge_connector.h:13:68: note: passing argument to parameter 'drm' here
   struct drm_connector *drm_bridge_connector_init(struct drm_device *drm,
                                                                      ^
   2 errors generated.


vim +56 drivers/gpu/drm/meson/meson_drv.h

    42	
    43	struct meson_drm {
    44		struct device *dev;
    45		enum vpu_compatible compat;
    46		void __iomem *io_base;
    47		struct regmap *hhi;
    48		int vsync_irq;
    49	
    50		struct meson_canvas *canvas;
    51		u8 canvas_id_osd1;
    52		u8 canvas_id_vd1_0;
    53		u8 canvas_id_vd1_1;
    54		u8 canvas_id_vd1_2;
    55	
  > 56		struct drm_device drm;
    57		struct drm_crtc *crtc;
    58		struct drm_plane *primary_plane;
    59		struct drm_plane *overlay_plane;
    60		void *encoders[MESON_ENC_LAST];
    61	
    62		const struct meson_drm_soc_limits *limits;
    63	
    64		/* Components Data */
    65		struct {
    66			bool osd1_enabled;
    67			bool osd1_interlace;
    68			bool osd1_commit;
    69			bool osd1_afbcd;
    70			uint32_t osd1_ctrl_stat;
    71			uint32_t osd1_ctrl_stat2;
    72			uint32_t osd1_blk0_cfg[5];
    73			uint32_t osd1_blk1_cfg4;
    74			uint32_t osd1_blk2_cfg4;
    75			uint32_t osd1_addr;
    76			uint32_t osd1_stride;
    77			uint32_t osd1_height;
    78			uint32_t osd1_width;
    79			uint32_t osd_sc_ctrl0;
    80			uint32_t osd_sc_i_wh_m1;
    81			uint32_t osd_sc_o_h_start_end;
    82			uint32_t osd_sc_o_v_start_end;
    83			uint32_t osd_sc_v_ini_phase;
    84			uint32_t osd_sc_v_phase_step;
    85			uint32_t osd_sc_h_ini_phase;
    86			uint32_t osd_sc_h_phase_step;
    87			uint32_t osd_sc_h_ctrl0;
    88			uint32_t osd_sc_v_ctrl0;
    89			uint32_t osd_blend_din0_scope_h;
    90			uint32_t osd_blend_din0_scope_v;
    91			uint32_t osb_blend0_size;
    92			uint32_t osb_blend1_size;
    93	
    94			bool vd1_enabled;
    95			bool vd1_commit;
    96			bool vd1_afbc;
    97			unsigned int vd1_planes;
    98			uint32_t vd1_if0_gen_reg;
    99			uint32_t vd1_if0_luma_x0;
   100			uint32_t vd1_if0_luma_y0;
   101			uint32_t vd1_if0_chroma_x0;
   102			uint32_t vd1_if0_chroma_y0;
   103			uint32_t vd1_if0_repeat_loop;
   104			uint32_t vd1_if0_luma0_rpt_pat;
   105			uint32_t vd1_if0_chroma0_rpt_pat;
   106			uint32_t vd1_range_map_y;
   107			uint32_t vd1_range_map_cb;
   108			uint32_t vd1_range_map_cr;
   109			uint32_t viu_vd1_fmt_w;
   110			uint32_t vd1_if0_canvas0;
   111			uint32_t vd1_if0_gen_reg2;
   112			uint32_t viu_vd1_fmt_ctrl;
   113			uint32_t vd1_addr0;
   114			uint32_t vd1_addr1;
   115			uint32_t vd1_addr2;
   116			uint32_t vd1_stride0;
   117			uint32_t vd1_stride1;
   118			uint32_t vd1_stride2;
   119			uint32_t vd1_height0;
   120			uint32_t vd1_height1;
   121			uint32_t vd1_height2;
   122			uint32_t vd1_afbc_mode;
   123			uint32_t vd1_afbc_en;
   124			uint32_t vd1_afbc_head_addr;
   125			uint32_t vd1_afbc_body_addr;
   126			uint32_t vd1_afbc_conv_ctrl;
   127			uint32_t vd1_afbc_dec_def_color;
   128			uint32_t vd1_afbc_vd_cfmt_ctrl;
   129			uint32_t vd1_afbc_vd_cfmt_w;
   130			uint32_t vd1_afbc_vd_cfmt_h;
   131			uint32_t vd1_afbc_mif_hor_scope;
   132			uint32_t vd1_afbc_mif_ver_scope;
   133			uint32_t vd1_afbc_size_out;
   134			uint32_t vd1_afbc_pixel_hor_scope;
   135			uint32_t vd1_afbc_pixel_ver_scope;
   136			uint32_t vd1_afbc_size_in;
   137			uint32_t vpp_pic_in_height;
   138			uint32_t vpp_postblend_vd1_h_start_end;
   139			uint32_t vpp_postblend_vd1_v_start_end;
   140			uint32_t vpp_hsc_region12_startp;
   141			uint32_t vpp_hsc_region34_startp;
   142			uint32_t vpp_hsc_region4_endp;
   143			uint32_t vpp_hsc_start_phase_step;
   144			uint32_t vpp_hsc_region1_phase_slope;
   145			uint32_t vpp_hsc_region3_phase_slope;
   146			uint32_t vpp_line_in_length;
   147			uint32_t vpp_preblend_h_size;
   148			uint32_t vpp_vsc_region12_startp;
   149			uint32_t vpp_vsc_region34_startp;
   150			uint32_t vpp_vsc_region4_endp;
   151			uint32_t vpp_vsc_start_phase_step;
   152			uint32_t vpp_vsc_ini_phase;
   153			uint32_t vpp_vsc_phase_ctrl;
   154			uint32_t vpp_hsc_phase_ctrl;
   155			uint32_t vpp_blend_vd2_h_start_end;
   156			uint32_t vpp_blend_vd2_v_start_end;
   157		} viu;
   158	
   159		struct {
   160			unsigned int current_mode;
   161			bool hdmi_repeat;
   162			bool venc_repeat;
   163			bool hdmi_use_enci;
   164		} venc;
   165	
   166		struct {
   167			dma_addr_t addr_dma;
   168			uint32_t *addr;
   169			unsigned int offset;
   170		} rdma;
   171	
   172		struct {
   173			struct meson_afbcd_ops *ops;
   174			u64 modifier;
   175			u32 format;
   176		} afbcd;
   177	};
   178	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
[PATCH v4] drm/meson: switch to a managed drm device
Posted by Anastasia Belova 1 year, 2 months ago
Switch to a managed drm device to cleanup some error handling
and make future work easier.

Fix dereference of NULL in meson_drv_bind_master by removing
drm_dev_put(drm) before meson_encoder_*_remove and
component_unbind_all where drm is dereferenced.

Co-developed by Linux Verification Center (linuxtesting.org).

Cc: stable@vger.kernel.org
Fixes: 6a044642988b ("drm/meson: fix unbind path if HDMI fails to bind")
Signed-off-by: Anastasia Belova <abelova@astralinux.ru>
---
v2: fix commit message and add Cc: stable@vger.kernel.org
v3: cleanup error paths
v4: fix build errors
 drivers/gpu/drm/meson/meson_crtc.c         | 10 +--
 drivers/gpu/drm/meson/meson_drv.c          | 93 ++++++++++------------
 drivers/gpu/drm/meson/meson_drv.h          |  3 +-
 drivers/gpu/drm/meson/meson_encoder_cvbs.c |  8 +-
 drivers/gpu/drm/meson/meson_encoder_dsi.c  |  2 +-
 drivers/gpu/drm/meson/meson_encoder_hdmi.c |  4 +-
 drivers/gpu/drm/meson/meson_overlay.c      |  8 +-
 drivers/gpu/drm/meson/meson_plane.c        | 10 +--
 8 files changed, 63 insertions(+), 75 deletions(-)

diff --git a/drivers/gpu/drm/meson/meson_crtc.c b/drivers/gpu/drm/meson/meson_crtc.c
index d70616da8ce2..e1c0bf3baeea 100644
--- a/drivers/gpu/drm/meson/meson_crtc.c
+++ b/drivers/gpu/drm/meson/meson_crtc.c
@@ -662,13 +662,13 @@ void meson_crtc_irq(struct meson_drm *priv)
 
 	drm_crtc_handle_vblank(priv->crtc);
 
-	spin_lock_irqsave(&priv->drm->event_lock, flags);
+	spin_lock_irqsave(&priv->drm.event_lock, flags);
 	if (meson_crtc->event) {
 		drm_crtc_send_vblank_event(priv->crtc, meson_crtc->event);
 		drm_crtc_vblank_put(priv->crtc);
 		meson_crtc->event = NULL;
 	}
-	spin_unlock_irqrestore(&priv->drm->event_lock, flags);
+	spin_unlock_irqrestore(&priv->drm.event_lock, flags);
 }
 
 int meson_crtc_create(struct meson_drm *priv)
@@ -677,18 +677,18 @@ int meson_crtc_create(struct meson_drm *priv)
 	struct drm_crtc *crtc;
 	int ret;
 
-	meson_crtc = devm_kzalloc(priv->drm->dev, sizeof(*meson_crtc),
+	meson_crtc = devm_kzalloc(priv->drm.dev, sizeof(*meson_crtc),
 				  GFP_KERNEL);
 	if (!meson_crtc)
 		return -ENOMEM;
 
 	meson_crtc->priv = priv;
 	crtc = &meson_crtc->base;
-	ret = drm_crtc_init_with_planes(priv->drm, crtc,
+	ret = drm_crtc_init_with_planes(&priv->drm, crtc,
 					priv->primary_plane, NULL,
 					&meson_crtc_funcs, "meson_crtc");
 	if (ret) {
-		dev_err(priv->drm->dev, "Failed to init CRTC\n");
+		dev_err(priv->drm.dev, "Failed to init CRTC\n");
 		return ret;
 	}
 
diff --git a/drivers/gpu/drm/meson/meson_drv.c b/drivers/gpu/drm/meson/meson_drv.c
index 4bd0baa2a4f5..dd87c6b61e9e 100644
--- a/drivers/gpu/drm/meson/meson_drv.c
+++ b/drivers/gpu/drm/meson/meson_drv.c
@@ -182,7 +182,6 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
 	struct platform_device *pdev = to_platform_device(dev);
 	const struct meson_drm_match_data *match;
 	struct meson_drm *priv;
-	struct drm_device *drm;
 	struct resource *res;
 	void __iomem *regs;
 	int ret, i;
@@ -197,58 +196,49 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
 	if (!match)
 		return -ENODEV;
 
-	drm = drm_dev_alloc(&meson_driver, dev);
-	if (IS_ERR(drm))
-		return PTR_ERR(drm);
+	priv = devm_drm_dev_alloc(dev, &meson_driver,
+				 struct meson_drm, drm);
 
-	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
-	if (!priv) {
-		ret = -ENOMEM;
-		goto free_drm;
-	}
-	drm->dev_private = priv;
-	priv->drm = drm;
+	if (IS_ERR(priv))
+		return PTR_ERR(priv);
+
+	priv->drm.dev_private = priv;
 	priv->dev = dev;
 	priv->compat = match->compat;
 	priv->afbcd.ops = match->afbcd_ops;
 
 	regs = devm_platform_ioremap_resource_byname(pdev, "vpu");
 	if (IS_ERR(regs)) {
-		ret = PTR_ERR(regs);
-		goto free_drm;
+		return PTR_ERR(regs);
 	}
 
 	priv->io_base = regs;
 
 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "hhi");
 	if (!res) {
-		ret = -EINVAL;
-		goto free_drm;
+		return -EINVAL;
 	}
 	/* Simply ioremap since it may be a shared register zone */
 	regs = devm_ioremap(dev, res->start, resource_size(res));
 	if (!regs) {
-		ret = -EADDRNOTAVAIL;
-		goto free_drm;
+		return -EADDRNOTAVAIL;
 	}
 
 	priv->hhi = devm_regmap_init_mmio(dev, regs,
 					  &meson_regmap_config);
 	if (IS_ERR(priv->hhi)) {
 		dev_err(&pdev->dev, "Couldn't create the HHI regmap\n");
-		ret = PTR_ERR(priv->hhi);
-		goto free_drm;
+		return PTR_ERR(priv->hhi);
 	}
 
 	priv->canvas = meson_canvas_get(dev);
 	if (IS_ERR(priv->canvas)) {
-		ret = PTR_ERR(priv->canvas);
-		goto free_drm;
+		return PTR_ERR(priv->canvas);
 	}
 
 	ret = meson_canvas_alloc(priv->canvas, &priv->canvas_id_osd1);
 	if (ret)
-		goto free_drm;
+		return ret;
 	ret = meson_canvas_alloc(priv->canvas, &priv->canvas_id_vd1_0);
 	if (ret)
 		goto free_canvas_osd1;
@@ -261,7 +251,7 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
 
 	priv->vsync_irq = platform_get_irq(pdev, 0);
 
-	ret = drm_vblank_init(drm, 1);
+	ret = drm_vblank_init(&priv->drm, 1);
 	if (ret)
 		goto free_canvas_vd1_2;
 
@@ -281,13 +271,13 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
 	if (ret)
 		goto free_canvas_vd1_2;
 
-	ret = drmm_mode_config_init(drm);
+	ret = drmm_mode_config_init(&priv->drm);
 	if (ret)
 		goto free_canvas_vd1_2;
-	drm->mode_config.max_width = 3840;
-	drm->mode_config.max_height = 2160;
-	drm->mode_config.funcs = &meson_mode_config_funcs;
-	drm->mode_config.helper_private	= &meson_mode_config_helpers;
+	priv->drm.mode_config.max_width = 3840;
+	priv->drm.mode_config.max_height = 2160;
+	priv->drm.mode_config.funcs = &meson_mode_config_funcs;
+	priv->drm.mode_config.helper_private = &meson_mode_config_helpers;
 
 	/* Hardware Initialization */
 
@@ -308,9 +298,9 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
 		goto exit_afbcd;
 
 	if (has_components) {
-		ret = component_bind_all(dev, drm);
+		ret = component_bind_all(dev, &priv->drm);
 		if (ret) {
-			dev_err(drm->dev, "Couldn't bind all components\n");
+			dev_err(priv->drm.dev, "Couldn't bind all components\n");
 			/* Do not try to unbind */
 			has_components = false;
 			goto exit_afbcd;
@@ -319,46 +309,49 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
 
 	ret = meson_encoder_hdmi_probe(priv);
 	if (ret)
-		goto exit_afbcd;
+		goto unbind_components;
 
 	if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) {
 		ret = meson_encoder_dsi_probe(priv);
 		if (ret)
-			goto exit_afbcd;
+			goto unbind_components;
 	}
 
 	ret = meson_plane_create(priv);
 	if (ret)
-		goto exit_afbcd;
+		goto unbind_components;
 
 	ret = meson_overlay_create(priv);
 	if (ret)
-		goto exit_afbcd;
+		goto unbind_components;
 
 	ret = meson_crtc_create(priv);
 	if (ret)
-		goto exit_afbcd;
+		goto unbind_components;
 
-	ret = request_irq(priv->vsync_irq, meson_irq, 0, drm->driver->name, drm);
+	ret = request_irq(priv->vsync_irq, meson_irq, 0, priv->drm.driver->name, &priv->drm);
 	if (ret)
-		goto exit_afbcd;
+		goto unbind_components;
 
-	drm_mode_config_reset(drm);
+	drm_mode_config_reset(&priv->drm);
 
-	drm_kms_helper_poll_init(drm);
+	drm_kms_helper_poll_init(&priv->drm);
 
 	platform_set_drvdata(pdev, priv);
 
-	ret = drm_dev_register(drm, 0);
+	ret = drm_dev_register(&priv->drm, 0);
 	if (ret)
 		goto uninstall_irq;
 
-	drm_fbdev_dma_setup(drm, 32);
+	drm_fbdev_dma_setup(&priv->drm, 32);
 
 	return 0;
 
 uninstall_irq:
-	free_irq(priv->vsync_irq, drm);
+	free_irq(priv->vsync_irq, &priv->drm);
+unbind_components:
+	if (has_components)
+		component_unbind_all(dev, &priv->drm);
 exit_afbcd:
 	if (priv->afbcd.ops)
 		priv->afbcd.ops->exit(priv);
@@ -370,16 +363,11 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
 	meson_canvas_free(priv->canvas, priv->canvas_id_vd1_0);
 free_canvas_osd1:
 	meson_canvas_free(priv->canvas, priv->canvas_id_osd1);
-free_drm:
-	drm_dev_put(drm);
 
 	meson_encoder_dsi_remove(priv);
 	meson_encoder_hdmi_remove(priv);
 	meson_encoder_cvbs_remove(priv);
 
-	if (has_components)
-		component_unbind_all(dev, drm);
-
 	return ret;
 }
 
@@ -391,7 +379,7 @@ static int meson_drv_bind(struct device *dev)
 static void meson_drv_unbind(struct device *dev)
 {
 	struct meson_drm *priv = dev_get_drvdata(dev);
-	struct drm_device *drm = priv->drm;
+	struct drm_device *drm = &priv->drm;
 
 	if (priv->canvas) {
 		meson_canvas_free(priv->canvas, priv->canvas_id_osd1);
@@ -404,7 +392,6 @@ static void meson_drv_unbind(struct device *dev)
 	drm_kms_helper_poll_fini(drm);
 	drm_atomic_helper_shutdown(drm);
 	free_irq(priv->vsync_irq, drm);
-	drm_dev_put(drm);
 
 	meson_encoder_dsi_remove(priv);
 	meson_encoder_hdmi_remove(priv);
@@ -428,7 +415,7 @@ static int __maybe_unused meson_drv_pm_suspend(struct device *dev)
 	if (!priv)
 		return 0;
 
-	return drm_mode_config_helper_suspend(priv->drm);
+	return drm_mode_config_helper_suspend(&priv->drm);
 }
 
 static int __maybe_unused meson_drv_pm_resume(struct device *dev)
@@ -445,7 +432,7 @@ static int __maybe_unused meson_drv_pm_resume(struct device *dev)
 	if (priv->afbcd.ops)
 		priv->afbcd.ops->init(priv);
 
-	return drm_mode_config_helper_resume(priv->drm);
+	return drm_mode_config_helper_resume(&priv->drm);
 }
 
 static void meson_drv_shutdown(struct platform_device *pdev)
@@ -455,8 +442,8 @@ static void meson_drv_shutdown(struct platform_device *pdev)
 	if (!priv)
 		return;
 
-	drm_kms_helper_poll_fini(priv->drm);
-	drm_atomic_helper_shutdown(priv->drm);
+	drm_kms_helper_poll_fini(&priv->drm);
+	drm_atomic_helper_shutdown(&priv->drm);
 }
 
 /*
diff --git a/drivers/gpu/drm/meson/meson_drv.h b/drivers/gpu/drm/meson/meson_drv.h
index 3f9345c14f31..45554c701322 100644
--- a/drivers/gpu/drm/meson/meson_drv.h
+++ b/drivers/gpu/drm/meson/meson_drv.h
@@ -8,6 +8,7 @@
 #define __MESON_DRV_H
 
 #include <linux/device.h>
+#include <drm/drm_device.h>
 #include <linux/of.h>
 #include <linux/regmap.h>
 
@@ -53,7 +54,7 @@ struct meson_drm {
 	u8 canvas_id_vd1_1;
 	u8 canvas_id_vd1_2;
 
-	struct drm_device *drm;
+	struct drm_device drm;
 	struct drm_crtc *crtc;
 	struct drm_plane *primary_plane;
 	struct drm_plane *overlay_plane;
diff --git a/drivers/gpu/drm/meson/meson_encoder_cvbs.c b/drivers/gpu/drm/meson/meson_encoder_cvbs.c
index d1191de855d9..ddca22c8c1ff 100644
--- a/drivers/gpu/drm/meson/meson_encoder_cvbs.c
+++ b/drivers/gpu/drm/meson/meson_encoder_cvbs.c
@@ -104,7 +104,7 @@ static int meson_encoder_cvbs_get_modes(struct drm_bridge *bridge,
 	for (i = 0; i < MESON_CVBS_MODES_COUNT; ++i) {
 		struct meson_cvbs_mode *meson_mode = &meson_cvbs_modes[i];
 
-		mode = drm_mode_duplicate(priv->drm, &meson_mode->mode);
+		mode = drm_mode_duplicate(&priv->drm, &meson_mode->mode);
 		if (!mode) {
 			dev_err(priv->dev, "Failed to create a new display mode\n");
 			return 0;
@@ -221,7 +221,7 @@ static const struct drm_bridge_funcs meson_encoder_cvbs_bridge_funcs = {
 
 int meson_encoder_cvbs_probe(struct meson_drm *priv)
 {
-	struct drm_device *drm = priv->drm;
+	struct drm_device *drm = &priv->drm;
 	struct meson_encoder_cvbs *meson_encoder_cvbs;
 	struct drm_connector *connector;
 	struct device_node *remote;
@@ -256,7 +256,7 @@ int meson_encoder_cvbs_probe(struct meson_drm *priv)
 	meson_encoder_cvbs->priv = priv;
 
 	/* Encoder */
-	ret = drm_simple_encoder_init(priv->drm, &meson_encoder_cvbs->encoder,
+	ret = drm_simple_encoder_init(&priv->drm, &meson_encoder_cvbs->encoder,
 				      DRM_MODE_ENCODER_TVDAC);
 	if (ret)
 		return dev_err_probe(priv->dev, ret,
@@ -273,7 +273,7 @@ int meson_encoder_cvbs_probe(struct meson_drm *priv)
 	}
 
 	/* Initialize & attach Bridge Connector */
-	connector = drm_bridge_connector_init(priv->drm, &meson_encoder_cvbs->encoder);
+	connector = drm_bridge_connector_init(&priv->drm, &meson_encoder_cvbs->encoder);
 	if (IS_ERR(connector))
 		return dev_err_probe(priv->dev, PTR_ERR(connector),
 				     "Unable to create CVBS bridge connector\n");
diff --git a/drivers/gpu/drm/meson/meson_encoder_dsi.c b/drivers/gpu/drm/meson/meson_encoder_dsi.c
index 7816902f5907..03bb12c69863 100644
--- a/drivers/gpu/drm/meson/meson_encoder_dsi.c
+++ b/drivers/gpu/drm/meson/meson_encoder_dsi.c
@@ -132,7 +132,7 @@ int meson_encoder_dsi_probe(struct meson_drm *priv)
 	meson_encoder_dsi->priv = priv;
 
 	/* Encoder */
-	ret = drm_simple_encoder_init(priv->drm, &meson_encoder_dsi->encoder,
+	ret = drm_simple_encoder_init(&priv->drm, &meson_encoder_dsi->encoder,
 				      DRM_MODE_ENCODER_DSI);
 	if (ret)
 		return dev_err_probe(priv->dev, ret,
diff --git a/drivers/gpu/drm/meson/meson_encoder_hdmi.c b/drivers/gpu/drm/meson/meson_encoder_hdmi.c
index 0593a1cde906..4465d987f85b 100644
--- a/drivers/gpu/drm/meson/meson_encoder_hdmi.c
+++ b/drivers/gpu/drm/meson/meson_encoder_hdmi.c
@@ -402,7 +402,7 @@ int meson_encoder_hdmi_probe(struct meson_drm *priv)
 	meson_encoder_hdmi->priv = priv;
 
 	/* Encoder */
-	ret = drm_simple_encoder_init(priv->drm, &meson_encoder_hdmi->encoder,
+	ret = drm_simple_encoder_init(&priv->drm, &meson_encoder_hdmi->encoder,
 				      DRM_MODE_ENCODER_TMDS);
 	if (ret) {
 		dev_err_probe(priv->dev, ret, "Failed to init HDMI encoder\n");
@@ -420,7 +420,7 @@ int meson_encoder_hdmi_probe(struct meson_drm *priv)
 	}
 
 	/* Initialize & attach Bridge Connector */
-	meson_encoder_hdmi->connector = drm_bridge_connector_init(priv->drm,
+	meson_encoder_hdmi->connector = drm_bridge_connector_init(&priv->drm,
 							&meson_encoder_hdmi->encoder);
 	if (IS_ERR(meson_encoder_hdmi->connector)) {
 		ret = dev_err_probe(priv->dev,
diff --git a/drivers/gpu/drm/meson/meson_overlay.c b/drivers/gpu/drm/meson/meson_overlay.c
index 7f98de38842b..60ee7f758723 100644
--- a/drivers/gpu/drm/meson/meson_overlay.c
+++ b/drivers/gpu/drm/meson/meson_overlay.c
@@ -484,7 +484,7 @@ static void meson_overlay_atomic_update(struct drm_plane *plane,
 
 	interlace_mode = new_state->crtc->mode.flags & DRM_MODE_FLAG_INTERLACE;
 
-	spin_lock_irqsave(&priv->drm->event_lock, flags);
+	spin_lock_irqsave(&priv->drm.event_lock, flags);
 
 	if ((fb->modifier & DRM_FORMAT_MOD_AMLOGIC_FBC(0, 0)) ==
 			    DRM_FORMAT_MOD_AMLOGIC_FBC(0, 0)) {
@@ -717,7 +717,7 @@ static void meson_overlay_atomic_update(struct drm_plane *plane,
 
 	priv->viu.vd1_enabled = true;
 
-	spin_unlock_irqrestore(&priv->drm->event_lock, flags);
+	spin_unlock_irqrestore(&priv->drm.event_lock, flags);
 
 	DRM_DEBUG_DRIVER("\n");
 }
@@ -838,7 +838,7 @@ int meson_overlay_create(struct meson_drm *priv)
 
 	DRM_DEBUG_DRIVER("\n");
 
-	meson_overlay = devm_kzalloc(priv->drm->dev, sizeof(*meson_overlay),
+	meson_overlay = devm_kzalloc(priv->drm.dev, sizeof(*meson_overlay),
 				   GFP_KERNEL);
 	if (!meson_overlay)
 		return -ENOMEM;
@@ -846,7 +846,7 @@ int meson_overlay_create(struct meson_drm *priv)
 	meson_overlay->priv = priv;
 	plane = &meson_overlay->base;
 
-	drm_universal_plane_init(priv->drm, plane, 0xFF,
+	drm_universal_plane_init(&priv->drm, plane, 0xFF,
 				 &meson_overlay_funcs,
 				 supported_drm_formats,
 				 ARRAY_SIZE(supported_drm_formats),
diff --git a/drivers/gpu/drm/meson/meson_plane.c b/drivers/gpu/drm/meson/meson_plane.c
index b43ac61201f3..13be94309bf4 100644
--- a/drivers/gpu/drm/meson/meson_plane.c
+++ b/drivers/gpu/drm/meson/meson_plane.c
@@ -157,7 +157,7 @@ static void meson_plane_atomic_update(struct drm_plane *plane,
 	 * Update Buffer
 	 * Enable Plane
 	 */
-	spin_lock_irqsave(&priv->drm->event_lock, flags);
+	spin_lock_irqsave(&priv->drm.event_lock, flags);
 
 	/* Check if AFBC decoder is required for this buffer */
 	if ((meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM) ||
@@ -393,7 +393,7 @@ static void meson_plane_atomic_update(struct drm_plane *plane,
 
 	priv->viu.osd1_enabled = true;
 
-	spin_unlock_irqrestore(&priv->drm->event_lock, flags);
+	spin_unlock_irqrestore(&priv->drm.event_lock, flags);
 }
 
 static void meson_plane_atomic_disable(struct drm_plane *plane,
@@ -536,7 +536,7 @@ int meson_plane_create(struct meson_drm *priv)
 	const uint64_t *format_modifiers = format_modifiers_default;
 	int ret;
 
-	meson_plane = devm_kzalloc(priv->drm->dev, sizeof(*meson_plane),
+	meson_plane = devm_kzalloc(priv->drm.dev, sizeof(*meson_plane),
 				   GFP_KERNEL);
 	if (!meson_plane)
 		return -ENOMEM;
@@ -549,14 +549,14 @@ int meson_plane_create(struct meson_drm *priv)
 	else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A))
 		format_modifiers = format_modifiers_afbc_g12a;
 
-	ret = drm_universal_plane_init(priv->drm, plane, 0xFF,
+	ret = drm_universal_plane_init(&priv->drm, plane, 0xFF,
 					&meson_plane_funcs,
 					supported_drm_formats,
 					ARRAY_SIZE(supported_drm_formats),
 					format_modifiers,
 					DRM_PLANE_TYPE_PRIMARY, "meson_primary_plane");
 	if (ret) {
-		devm_kfree(priv->drm->dev, meson_plane);
+		devm_kfree(priv->drm.dev, meson_plane);
 		return ret;
 	}
 
-- 
2.43.0
Re: [PATCH v4] drm/meson: switch to a managed drm device
Posted by Anastasia Belova 1 year, 2 months ago
Just a friendly reminder.

09/10/24 16:15, Anastasia Belova пишет:
> Switch to a managed drm device to cleanup some error handling
> and make future work easier.
>
> Fix dereference of NULL in meson_drv_bind_master by removing
> drm_dev_put(drm) before meson_encoder_*_remove and
> component_unbind_all where drm is dereferenced.
>
> Co-developed by Linux Verification Center (linuxtesting.org).
>
> Cc: stable@vger.kernel.org
> Fixes: 6a044642988b ("drm/meson: fix unbind path if HDMI fails to bind")
> Signed-off-by: Anastasia Belova <abelova@astralinux.ru>
> ---
> v2: fix commit message and add Cc: stable@vger.kernel.org
> v3: cleanup error paths
> v4: fix build errors
>   drivers/gpu/drm/meson/meson_crtc.c         | 10 +--
>   drivers/gpu/drm/meson/meson_drv.c          | 93 ++++++++++------------
>   drivers/gpu/drm/meson/meson_drv.h          |  3 +-
>   drivers/gpu/drm/meson/meson_encoder_cvbs.c |  8 +-
>   drivers/gpu/drm/meson/meson_encoder_dsi.c  |  2 +-
>   drivers/gpu/drm/meson/meson_encoder_hdmi.c |  4 +-
>   drivers/gpu/drm/meson/meson_overlay.c      |  8 +-
>   drivers/gpu/drm/meson/meson_plane.c        | 10 +--
>   8 files changed, 63 insertions(+), 75 deletions(-)
>
> diff --git a/drivers/gpu/drm/meson/meson_crtc.c b/drivers/gpu/drm/meson/meson_crtc.c
> index d70616da8ce2..e1c0bf3baeea 100644
> --- a/drivers/gpu/drm/meson/meson_crtc.c
> +++ b/drivers/gpu/drm/meson/meson_crtc.c
> @@ -662,13 +662,13 @@ void meson_crtc_irq(struct meson_drm *priv)
>   
>   	drm_crtc_handle_vblank(priv->crtc);
>   
> -	spin_lock_irqsave(&priv->drm->event_lock, flags);
> +	spin_lock_irqsave(&priv->drm.event_lock, flags);
>   	if (meson_crtc->event) {
>   		drm_crtc_send_vblank_event(priv->crtc, meson_crtc->event);
>   		drm_crtc_vblank_put(priv->crtc);
>   		meson_crtc->event = NULL;
>   	}
> -	spin_unlock_irqrestore(&priv->drm->event_lock, flags);
> +	spin_unlock_irqrestore(&priv->drm.event_lock, flags);
>   }
>   
>   int meson_crtc_create(struct meson_drm *priv)
> @@ -677,18 +677,18 @@ int meson_crtc_create(struct meson_drm *priv)
>   	struct drm_crtc *crtc;
>   	int ret;
>   
> -	meson_crtc = devm_kzalloc(priv->drm->dev, sizeof(*meson_crtc),
> +	meson_crtc = devm_kzalloc(priv->drm.dev, sizeof(*meson_crtc),
>   				  GFP_KERNEL);
>   	if (!meson_crtc)
>   		return -ENOMEM;
>   
>   	meson_crtc->priv = priv;
>   	crtc = &meson_crtc->base;
> -	ret = drm_crtc_init_with_planes(priv->drm, crtc,
> +	ret = drm_crtc_init_with_planes(&priv->drm, crtc,
>   					priv->primary_plane, NULL,
>   					&meson_crtc_funcs, "meson_crtc");
>   	if (ret) {
> -		dev_err(priv->drm->dev, "Failed to init CRTC\n");
> +		dev_err(priv->drm.dev, "Failed to init CRTC\n");
>   		return ret;
>   	}
>   
> diff --git a/drivers/gpu/drm/meson/meson_drv.c b/drivers/gpu/drm/meson/meson_drv.c
> index 4bd0baa2a4f5..dd87c6b61e9e 100644
> --- a/drivers/gpu/drm/meson/meson_drv.c
> +++ b/drivers/gpu/drm/meson/meson_drv.c
> @@ -182,7 +182,6 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
>   	struct platform_device *pdev = to_platform_device(dev);
>   	const struct meson_drm_match_data *match;
>   	struct meson_drm *priv;
> -	struct drm_device *drm;
>   	struct resource *res;
>   	void __iomem *regs;
>   	int ret, i;
> @@ -197,58 +196,49 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
>   	if (!match)
>   		return -ENODEV;
>   
> -	drm = drm_dev_alloc(&meson_driver, dev);
> -	if (IS_ERR(drm))
> -		return PTR_ERR(drm);
> +	priv = devm_drm_dev_alloc(dev, &meson_driver,
> +				 struct meson_drm, drm);
>   
> -	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> -	if (!priv) {
> -		ret = -ENOMEM;
> -		goto free_drm;
> -	}
> -	drm->dev_private = priv;
> -	priv->drm = drm;
> +	if (IS_ERR(priv))
> +		return PTR_ERR(priv);
> +
> +	priv->drm.dev_private = priv;
>   	priv->dev = dev;
>   	priv->compat = match->compat;
>   	priv->afbcd.ops = match->afbcd_ops;
>   
>   	regs = devm_platform_ioremap_resource_byname(pdev, "vpu");
>   	if (IS_ERR(regs)) {
> -		ret = PTR_ERR(regs);
> -		goto free_drm;
> +		return PTR_ERR(regs);
>   	}
>   
>   	priv->io_base = regs;
>   
>   	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "hhi");
>   	if (!res) {
> -		ret = -EINVAL;
> -		goto free_drm;
> +		return -EINVAL;
>   	}
>   	/* Simply ioremap since it may be a shared register zone */
>   	regs = devm_ioremap(dev, res->start, resource_size(res));
>   	if (!regs) {
> -		ret = -EADDRNOTAVAIL;
> -		goto free_drm;
> +		return -EADDRNOTAVAIL;
>   	}
>   
>   	priv->hhi = devm_regmap_init_mmio(dev, regs,
>   					  &meson_regmap_config);
>   	if (IS_ERR(priv->hhi)) {
>   		dev_err(&pdev->dev, "Couldn't create the HHI regmap\n");
> -		ret = PTR_ERR(priv->hhi);
> -		goto free_drm;
> +		return PTR_ERR(priv->hhi);
>   	}
>   
>   	priv->canvas = meson_canvas_get(dev);
>   	if (IS_ERR(priv->canvas)) {
> -		ret = PTR_ERR(priv->canvas);
> -		goto free_drm;
> +		return PTR_ERR(priv->canvas);
>   	}
>   
>   	ret = meson_canvas_alloc(priv->canvas, &priv->canvas_id_osd1);
>   	if (ret)
> -		goto free_drm;
> +		return ret;
>   	ret = meson_canvas_alloc(priv->canvas, &priv->canvas_id_vd1_0);
>   	if (ret)
>   		goto free_canvas_osd1;
> @@ -261,7 +251,7 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
>   
>   	priv->vsync_irq = platform_get_irq(pdev, 0);
>   
> -	ret = drm_vblank_init(drm, 1);
> +	ret = drm_vblank_init(&priv->drm, 1);
>   	if (ret)
>   		goto free_canvas_vd1_2;
>   
> @@ -281,13 +271,13 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
>   	if (ret)
>   		goto free_canvas_vd1_2;
>   
> -	ret = drmm_mode_config_init(drm);
> +	ret = drmm_mode_config_init(&priv->drm);
>   	if (ret)
>   		goto free_canvas_vd1_2;
> -	drm->mode_config.max_width = 3840;
> -	drm->mode_config.max_height = 2160;
> -	drm->mode_config.funcs = &meson_mode_config_funcs;
> -	drm->mode_config.helper_private	= &meson_mode_config_helpers;
> +	priv->drm.mode_config.max_width = 3840;
> +	priv->drm.mode_config.max_height = 2160;
> +	priv->drm.mode_config.funcs = &meson_mode_config_funcs;
> +	priv->drm.mode_config.helper_private = &meson_mode_config_helpers;
>   
>   	/* Hardware Initialization */
>   
> @@ -308,9 +298,9 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
>   		goto exit_afbcd;
>   
>   	if (has_components) {
> -		ret = component_bind_all(dev, drm);
> +		ret = component_bind_all(dev, &priv->drm);
>   		if (ret) {
> -			dev_err(drm->dev, "Couldn't bind all components\n");
> +			dev_err(priv->drm.dev, "Couldn't bind all components\n");
>   			/* Do not try to unbind */
>   			has_components = false;
>   			goto exit_afbcd;
> @@ -319,46 +309,49 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
>   
>   	ret = meson_encoder_hdmi_probe(priv);
>   	if (ret)
> -		goto exit_afbcd;
> +		goto unbind_components;
>   
>   	if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) {
>   		ret = meson_encoder_dsi_probe(priv);
>   		if (ret)
> -			goto exit_afbcd;
> +			goto unbind_components;
>   	}
>   
>   	ret = meson_plane_create(priv);
>   	if (ret)
> -		goto exit_afbcd;
> +		goto unbind_components;
>   
>   	ret = meson_overlay_create(priv);
>   	if (ret)
> -		goto exit_afbcd;
> +		goto unbind_components;
>   
>   	ret = meson_crtc_create(priv);
>   	if (ret)
> -		goto exit_afbcd;
> +		goto unbind_components;
>   
> -	ret = request_irq(priv->vsync_irq, meson_irq, 0, drm->driver->name, drm);
> +	ret = request_irq(priv->vsync_irq, meson_irq, 0, priv->drm.driver->name, &priv->drm);
>   	if (ret)
> -		goto exit_afbcd;
> +		goto unbind_components;
>   
> -	drm_mode_config_reset(drm);
> +	drm_mode_config_reset(&priv->drm);
>   
> -	drm_kms_helper_poll_init(drm);
> +	drm_kms_helper_poll_init(&priv->drm);
>   
>   	platform_set_drvdata(pdev, priv);
>   
> -	ret = drm_dev_register(drm, 0);
> +	ret = drm_dev_register(&priv->drm, 0);
>   	if (ret)
>   		goto uninstall_irq;
>   
> -	drm_fbdev_dma_setup(drm, 32);
> +	drm_fbdev_dma_setup(&priv->drm, 32);
>   
>   	return 0;
>   
>   uninstall_irq:
> -	free_irq(priv->vsync_irq, drm);
> +	free_irq(priv->vsync_irq, &priv->drm);
> +unbind_components:
> +	if (has_components)
> +		component_unbind_all(dev, &priv->drm);
>   exit_afbcd:
>   	if (priv->afbcd.ops)
>   		priv->afbcd.ops->exit(priv);
> @@ -370,16 +363,11 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
>   	meson_canvas_free(priv->canvas, priv->canvas_id_vd1_0);
>   free_canvas_osd1:
>   	meson_canvas_free(priv->canvas, priv->canvas_id_osd1);
> -free_drm:
> -	drm_dev_put(drm);
>   
>   	meson_encoder_dsi_remove(priv);
>   	meson_encoder_hdmi_remove(priv);
>   	meson_encoder_cvbs_remove(priv);
>   
> -	if (has_components)
> -		component_unbind_all(dev, drm);
> -
>   	return ret;
>   }
>   
> @@ -391,7 +379,7 @@ static int meson_drv_bind(struct device *dev)
>   static void meson_drv_unbind(struct device *dev)
>   {
>   	struct meson_drm *priv = dev_get_drvdata(dev);
> -	struct drm_device *drm = priv->drm;
> +	struct drm_device *drm = &priv->drm;
>   
>   	if (priv->canvas) {
>   		meson_canvas_free(priv->canvas, priv->canvas_id_osd1);
> @@ -404,7 +392,6 @@ static void meson_drv_unbind(struct device *dev)
>   	drm_kms_helper_poll_fini(drm);
>   	drm_atomic_helper_shutdown(drm);
>   	free_irq(priv->vsync_irq, drm);
> -	drm_dev_put(drm);
>   
>   	meson_encoder_dsi_remove(priv);
>   	meson_encoder_hdmi_remove(priv);
> @@ -428,7 +415,7 @@ static int __maybe_unused meson_drv_pm_suspend(struct device *dev)
>   	if (!priv)
>   		return 0;
>   
> -	return drm_mode_config_helper_suspend(priv->drm);
> +	return drm_mode_config_helper_suspend(&priv->drm);
>   }
>   
>   static int __maybe_unused meson_drv_pm_resume(struct device *dev)
> @@ -445,7 +432,7 @@ static int __maybe_unused meson_drv_pm_resume(struct device *dev)
>   	if (priv->afbcd.ops)
>   		priv->afbcd.ops->init(priv);
>   
> -	return drm_mode_config_helper_resume(priv->drm);
> +	return drm_mode_config_helper_resume(&priv->drm);
>   }
>   
>   static void meson_drv_shutdown(struct platform_device *pdev)
> @@ -455,8 +442,8 @@ static void meson_drv_shutdown(struct platform_device *pdev)
>   	if (!priv)
>   		return;
>   
> -	drm_kms_helper_poll_fini(priv->drm);
> -	drm_atomic_helper_shutdown(priv->drm);
> +	drm_kms_helper_poll_fini(&priv->drm);
> +	drm_atomic_helper_shutdown(&priv->drm);
>   }
>   
>   /*
> diff --git a/drivers/gpu/drm/meson/meson_drv.h b/drivers/gpu/drm/meson/meson_drv.h
> index 3f9345c14f31..45554c701322 100644
> --- a/drivers/gpu/drm/meson/meson_drv.h
> +++ b/drivers/gpu/drm/meson/meson_drv.h
> @@ -8,6 +8,7 @@
>   #define __MESON_DRV_H
>   
>   #include <linux/device.h>
> +#include <drm/drm_device.h>
>   #include <linux/of.h>
>   #include <linux/regmap.h>
>   
> @@ -53,7 +54,7 @@ struct meson_drm {
>   	u8 canvas_id_vd1_1;
>   	u8 canvas_id_vd1_2;
>   
> -	struct drm_device *drm;
> +	struct drm_device drm;
>   	struct drm_crtc *crtc;
>   	struct drm_plane *primary_plane;
>   	struct drm_plane *overlay_plane;
> diff --git a/drivers/gpu/drm/meson/meson_encoder_cvbs.c b/drivers/gpu/drm/meson/meson_encoder_cvbs.c
> index d1191de855d9..ddca22c8c1ff 100644
> --- a/drivers/gpu/drm/meson/meson_encoder_cvbs.c
> +++ b/drivers/gpu/drm/meson/meson_encoder_cvbs.c
> @@ -104,7 +104,7 @@ static int meson_encoder_cvbs_get_modes(struct drm_bridge *bridge,
>   	for (i = 0; i < MESON_CVBS_MODES_COUNT; ++i) {
>   		struct meson_cvbs_mode *meson_mode = &meson_cvbs_modes[i];
>   
> -		mode = drm_mode_duplicate(priv->drm, &meson_mode->mode);
> +		mode = drm_mode_duplicate(&priv->drm, &meson_mode->mode);
>   		if (!mode) {
>   			dev_err(priv->dev, "Failed to create a new display mode\n");
>   			return 0;
> @@ -221,7 +221,7 @@ static const struct drm_bridge_funcs meson_encoder_cvbs_bridge_funcs = {
>   
>   int meson_encoder_cvbs_probe(struct meson_drm *priv)
>   {
> -	struct drm_device *drm = priv->drm;
> +	struct drm_device *drm = &priv->drm;
>   	struct meson_encoder_cvbs *meson_encoder_cvbs;
>   	struct drm_connector *connector;
>   	struct device_node *remote;
> @@ -256,7 +256,7 @@ int meson_encoder_cvbs_probe(struct meson_drm *priv)
>   	meson_encoder_cvbs->priv = priv;
>   
>   	/* Encoder */
> -	ret = drm_simple_encoder_init(priv->drm, &meson_encoder_cvbs->encoder,
> +	ret = drm_simple_encoder_init(&priv->drm, &meson_encoder_cvbs->encoder,
>   				      DRM_MODE_ENCODER_TVDAC);
>   	if (ret)
>   		return dev_err_probe(priv->dev, ret,
> @@ -273,7 +273,7 @@ int meson_encoder_cvbs_probe(struct meson_drm *priv)
>   	}
>   
>   	/* Initialize & attach Bridge Connector */
> -	connector = drm_bridge_connector_init(priv->drm, &meson_encoder_cvbs->encoder);
> +	connector = drm_bridge_connector_init(&priv->drm, &meson_encoder_cvbs->encoder);
>   	if (IS_ERR(connector))
>   		return dev_err_probe(priv->dev, PTR_ERR(connector),
>   				     "Unable to create CVBS bridge connector\n");
> diff --git a/drivers/gpu/drm/meson/meson_encoder_dsi.c b/drivers/gpu/drm/meson/meson_encoder_dsi.c
> index 7816902f5907..03bb12c69863 100644
> --- a/drivers/gpu/drm/meson/meson_encoder_dsi.c
> +++ b/drivers/gpu/drm/meson/meson_encoder_dsi.c
> @@ -132,7 +132,7 @@ int meson_encoder_dsi_probe(struct meson_drm *priv)
>   	meson_encoder_dsi->priv = priv;
>   
>   	/* Encoder */
> -	ret = drm_simple_encoder_init(priv->drm, &meson_encoder_dsi->encoder,
> +	ret = drm_simple_encoder_init(&priv->drm, &meson_encoder_dsi->encoder,
>   				      DRM_MODE_ENCODER_DSI);
>   	if (ret)
>   		return dev_err_probe(priv->dev, ret,
> diff --git a/drivers/gpu/drm/meson/meson_encoder_hdmi.c b/drivers/gpu/drm/meson/meson_encoder_hdmi.c
> index 0593a1cde906..4465d987f85b 100644
> --- a/drivers/gpu/drm/meson/meson_encoder_hdmi.c
> +++ b/drivers/gpu/drm/meson/meson_encoder_hdmi.c
> @@ -402,7 +402,7 @@ int meson_encoder_hdmi_probe(struct meson_drm *priv)
>   	meson_encoder_hdmi->priv = priv;
>   
>   	/* Encoder */
> -	ret = drm_simple_encoder_init(priv->drm, &meson_encoder_hdmi->encoder,
> +	ret = drm_simple_encoder_init(&priv->drm, &meson_encoder_hdmi->encoder,
>   				      DRM_MODE_ENCODER_TMDS);
>   	if (ret) {
>   		dev_err_probe(priv->dev, ret, "Failed to init HDMI encoder\n");
> @@ -420,7 +420,7 @@ int meson_encoder_hdmi_probe(struct meson_drm *priv)
>   	}
>   
>   	/* Initialize & attach Bridge Connector */
> -	meson_encoder_hdmi->connector = drm_bridge_connector_init(priv->drm,
> +	meson_encoder_hdmi->connector = drm_bridge_connector_init(&priv->drm,
>   							&meson_encoder_hdmi->encoder);
>   	if (IS_ERR(meson_encoder_hdmi->connector)) {
>   		ret = dev_err_probe(priv->dev,
> diff --git a/drivers/gpu/drm/meson/meson_overlay.c b/drivers/gpu/drm/meson/meson_overlay.c
> index 7f98de38842b..60ee7f758723 100644
> --- a/drivers/gpu/drm/meson/meson_overlay.c
> +++ b/drivers/gpu/drm/meson/meson_overlay.c
> @@ -484,7 +484,7 @@ static void meson_overlay_atomic_update(struct drm_plane *plane,
>   
>   	interlace_mode = new_state->crtc->mode.flags & DRM_MODE_FLAG_INTERLACE;
>   
> -	spin_lock_irqsave(&priv->drm->event_lock, flags);
> +	spin_lock_irqsave(&priv->drm.event_lock, flags);
>   
>   	if ((fb->modifier & DRM_FORMAT_MOD_AMLOGIC_FBC(0, 0)) ==
>   			    DRM_FORMAT_MOD_AMLOGIC_FBC(0, 0)) {
> @@ -717,7 +717,7 @@ static void meson_overlay_atomic_update(struct drm_plane *plane,
>   
>   	priv->viu.vd1_enabled = true;
>   
> -	spin_unlock_irqrestore(&priv->drm->event_lock, flags);
> +	spin_unlock_irqrestore(&priv->drm.event_lock, flags);
>   
>   	DRM_DEBUG_DRIVER("\n");
>   }
> @@ -838,7 +838,7 @@ int meson_overlay_create(struct meson_drm *priv)
>   
>   	DRM_DEBUG_DRIVER("\n");
>   
> -	meson_overlay = devm_kzalloc(priv->drm->dev, sizeof(*meson_overlay),
> +	meson_overlay = devm_kzalloc(priv->drm.dev, sizeof(*meson_overlay),
>   				   GFP_KERNEL);
>   	if (!meson_overlay)
>   		return -ENOMEM;
> @@ -846,7 +846,7 @@ int meson_overlay_create(struct meson_drm *priv)
>   	meson_overlay->priv = priv;
>   	plane = &meson_overlay->base;
>   
> -	drm_universal_plane_init(priv->drm, plane, 0xFF,
> +	drm_universal_plane_init(&priv->drm, plane, 0xFF,
>   				 &meson_overlay_funcs,
>   				 supported_drm_formats,
>   				 ARRAY_SIZE(supported_drm_formats),
> diff --git a/drivers/gpu/drm/meson/meson_plane.c b/drivers/gpu/drm/meson/meson_plane.c
> index b43ac61201f3..13be94309bf4 100644
> --- a/drivers/gpu/drm/meson/meson_plane.c
> +++ b/drivers/gpu/drm/meson/meson_plane.c
> @@ -157,7 +157,7 @@ static void meson_plane_atomic_update(struct drm_plane *plane,
>   	 * Update Buffer
>   	 * Enable Plane
>   	 */
> -	spin_lock_irqsave(&priv->drm->event_lock, flags);
> +	spin_lock_irqsave(&priv->drm.event_lock, flags);
>   
>   	/* Check if AFBC decoder is required for this buffer */
>   	if ((meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM) ||
> @@ -393,7 +393,7 @@ static void meson_plane_atomic_update(struct drm_plane *plane,
>   
>   	priv->viu.osd1_enabled = true;
>   
> -	spin_unlock_irqrestore(&priv->drm->event_lock, flags);
> +	spin_unlock_irqrestore(&priv->drm.event_lock, flags);
>   }
>   
>   static void meson_plane_atomic_disable(struct drm_plane *plane,
> @@ -536,7 +536,7 @@ int meson_plane_create(struct meson_drm *priv)
>   	const uint64_t *format_modifiers = format_modifiers_default;
>   	int ret;
>   
> -	meson_plane = devm_kzalloc(priv->drm->dev, sizeof(*meson_plane),
> +	meson_plane = devm_kzalloc(priv->drm.dev, sizeof(*meson_plane),
>   				   GFP_KERNEL);
>   	if (!meson_plane)
>   		return -ENOMEM;
> @@ -549,14 +549,14 @@ int meson_plane_create(struct meson_drm *priv)
>   	else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A))
>   		format_modifiers = format_modifiers_afbc_g12a;
>   
> -	ret = drm_universal_plane_init(priv->drm, plane, 0xFF,
> +	ret = drm_universal_plane_init(&priv->drm, plane, 0xFF,
>   					&meson_plane_funcs,
>   					supported_drm_formats,
>   					ARRAY_SIZE(supported_drm_formats),
>   					format_modifiers,
>   					DRM_PLANE_TYPE_PRIMARY, "meson_primary_plane");
>   	if (ret) {
> -		devm_kfree(priv->drm->dev, meson_plane);
> +		devm_kfree(priv->drm.dev, meson_plane);
>   		return ret;
>   	}
>   

Re: [PATCH v2] drm/meson: switch to a managed drm device
Posted by Anastasia Belova 1 year, 3 months ago
Hi,

It's just a friendly reminder.

Anastasia Belova

10/09/24 18:16, Anastasia Belova пишет:
> Switch to a managed drm device to cleanup some error handling
> and make future work easier.
>
> Fix dereference of NULL in meson_drv_bind_master by removing
> drm_dev_put(drm) before meson_encoder_*_remove and
> component_unbind_all where drm is dereferenced.
>
> Co-developed by Linux Verification Center (linuxtesting.org).
>
> Cc: stable@vger.kernel.org # 6.5
> Fixes: 6a044642988b ("drm/meson: fix unbind path if HDMI fails to bind")
> Signed-off-by: Anastasia Belova <abelova@astralinux.ru>
> ---
> v2: fix commit message and add Cc: stable@vger.kernel.org
>   drivers/gpu/drm/meson/meson_crtc.c         | 10 +--
>   drivers/gpu/drm/meson/meson_drv.c          | 71 ++++++++++------------
>   drivers/gpu/drm/meson/meson_drv.h          |  2 +-
>   drivers/gpu/drm/meson/meson_encoder_cvbs.c |  8 +--
>   drivers/gpu/drm/meson/meson_overlay.c      |  8 +--
>   drivers/gpu/drm/meson/meson_plane.c        | 10 +--
>   6 files changed, 51 insertions(+), 58 deletions(-)
>
> diff --git a/drivers/gpu/drm/meson/meson_crtc.c b/drivers/gpu/drm/meson/meson_crtc.c
> index d70616da8ce2..e1c0bf3baeea 100644
> --- a/drivers/gpu/drm/meson/meson_crtc.c
> +++ b/drivers/gpu/drm/meson/meson_crtc.c
> @@ -662,13 +662,13 @@ void meson_crtc_irq(struct meson_drm *priv)
>   
>   	drm_crtc_handle_vblank(priv->crtc);
>   
> -	spin_lock_irqsave(&priv->drm->event_lock, flags);
> +	spin_lock_irqsave(&priv->drm.event_lock, flags);
>   	if (meson_crtc->event) {
>   		drm_crtc_send_vblank_event(priv->crtc, meson_crtc->event);
>   		drm_crtc_vblank_put(priv->crtc);
>   		meson_crtc->event = NULL;
>   	}
> -	spin_unlock_irqrestore(&priv->drm->event_lock, flags);
> +	spin_unlock_irqrestore(&priv->drm.event_lock, flags);
>   }
>   
>   int meson_crtc_create(struct meson_drm *priv)
> @@ -677,18 +677,18 @@ int meson_crtc_create(struct meson_drm *priv)
>   	struct drm_crtc *crtc;
>   	int ret;
>   
> -	meson_crtc = devm_kzalloc(priv->drm->dev, sizeof(*meson_crtc),
> +	meson_crtc = devm_kzalloc(priv->drm.dev, sizeof(*meson_crtc),
>   				  GFP_KERNEL);
>   	if (!meson_crtc)
>   		return -ENOMEM;
>   
>   	meson_crtc->priv = priv;
>   	crtc = &meson_crtc->base;
> -	ret = drm_crtc_init_with_planes(priv->drm, crtc,
> +	ret = drm_crtc_init_with_planes(&priv->drm, crtc,
>   					priv->primary_plane, NULL,
>   					&meson_crtc_funcs, "meson_crtc");
>   	if (ret) {
> -		dev_err(priv->drm->dev, "Failed to init CRTC\n");
> +		dev_err(priv->drm.dev, "Failed to init CRTC\n");
>   		return ret;
>   	}
>   
> diff --git a/drivers/gpu/drm/meson/meson_drv.c b/drivers/gpu/drm/meson/meson_drv.c
> index 4bd0baa2a4f5..2e7c2e7c7b82 100644
> --- a/drivers/gpu/drm/meson/meson_drv.c
> +++ b/drivers/gpu/drm/meson/meson_drv.c
> @@ -182,7 +182,6 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
>   	struct platform_device *pdev = to_platform_device(dev);
>   	const struct meson_drm_match_data *match;
>   	struct meson_drm *priv;
> -	struct drm_device *drm;
>   	struct resource *res;
>   	void __iomem *regs;
>   	int ret, i;
> @@ -197,17 +196,13 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
>   	if (!match)
>   		return -ENODEV;
>   
> -	drm = drm_dev_alloc(&meson_driver, dev);
> -	if (IS_ERR(drm))
> -		return PTR_ERR(drm);
> +	priv = devm_drm_dev_alloc(dev, &meson_driver,
> +				 struct meson_drm, drm);
>   
> -	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> -	if (!priv) {
> -		ret = -ENOMEM;
> -		goto free_drm;
> -	}
> -	drm->dev_private = priv;
> -	priv->drm = drm;
> +	if (IS_ERR(priv))
> +		return PTR_ERR(priv);
> +
> +	priv->drm.dev_private = priv;
>   	priv->dev = dev;
>   	priv->compat = match->compat;
>   	priv->afbcd.ops = match->afbcd_ops;
> @@ -215,7 +210,7 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
>   	regs = devm_platform_ioremap_resource_byname(pdev, "vpu");
>   	if (IS_ERR(regs)) {
>   		ret = PTR_ERR(regs);
> -		goto free_drm;
> +		goto remove_encoders;
>   	}
>   
>   	priv->io_base = regs;
> @@ -223,13 +218,13 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
>   	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "hhi");
>   	if (!res) {
>   		ret = -EINVAL;
> -		goto free_drm;
> +		goto remove_encoders;
>   	}
>   	/* Simply ioremap since it may be a shared register zone */
>   	regs = devm_ioremap(dev, res->start, resource_size(res));
>   	if (!regs) {
>   		ret = -EADDRNOTAVAIL;
> -		goto free_drm;
> +		goto remove_encoders;
>   	}
>   
>   	priv->hhi = devm_regmap_init_mmio(dev, regs,
> @@ -237,18 +232,18 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
>   	if (IS_ERR(priv->hhi)) {
>   		dev_err(&pdev->dev, "Couldn't create the HHI regmap\n");
>   		ret = PTR_ERR(priv->hhi);
> -		goto free_drm;
> +		goto remove_encoders;
>   	}
>   
>   	priv->canvas = meson_canvas_get(dev);
>   	if (IS_ERR(priv->canvas)) {
>   		ret = PTR_ERR(priv->canvas);
> -		goto free_drm;
> +		goto remove_encoders;
>   	}
>   
>   	ret = meson_canvas_alloc(priv->canvas, &priv->canvas_id_osd1);
>   	if (ret)
> -		goto free_drm;
> +		goto remove_encoders;
>   	ret = meson_canvas_alloc(priv->canvas, &priv->canvas_id_vd1_0);
>   	if (ret)
>   		goto free_canvas_osd1;
> @@ -261,7 +256,7 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
>   
>   	priv->vsync_irq = platform_get_irq(pdev, 0);
>   
> -	ret = drm_vblank_init(drm, 1);
> +	ret = drm_vblank_init(&priv->drm, 1);
>   	if (ret)
>   		goto free_canvas_vd1_2;
>   
> @@ -284,10 +279,10 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
>   	ret = drmm_mode_config_init(drm);
>   	if (ret)
>   		goto free_canvas_vd1_2;
> -	drm->mode_config.max_width = 3840;
> -	drm->mode_config.max_height = 2160;
> -	drm->mode_config.funcs = &meson_mode_config_funcs;
> -	drm->mode_config.helper_private	= &meson_mode_config_helpers;
> +	priv->drm.mode_config.max_width = 3840;
> +	priv->drm.mode_config.max_height = 2160;
> +	priv->drm.mode_config.funcs = &meson_mode_config_funcs;
> +	priv->drm.mode_config.helper_private = &meson_mode_config_helpers;
>   
>   	/* Hardware Initialization */
>   
> @@ -308,9 +303,9 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
>   		goto exit_afbcd;
>   
>   	if (has_components) {
> -		ret = component_bind_all(dev, drm);
> +		ret = component_bind_all(dev, &priv->drm);
>   		if (ret) {
> -			dev_err(drm->dev, "Couldn't bind all components\n");
> +			dev_err(priv->drm.dev, "Couldn't bind all components\n");
>   			/* Do not try to unbind */
>   			has_components = false;
>   			goto exit_afbcd;
> @@ -339,26 +334,26 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
>   	if (ret)
>   		goto exit_afbcd;
>   
> -	ret = request_irq(priv->vsync_irq, meson_irq, 0, drm->driver->name, drm);
> +	ret = request_irq(priv->vsync_irq, meson_irq, 0, priv->drm.driver->name, &priv->drm);
>   	if (ret)
>   		goto exit_afbcd;
>   
> -	drm_mode_config_reset(drm);
> +	drm_mode_config_reset(&priv->drm);
>   
> -	drm_kms_helper_poll_init(drm);
> +	drm_kms_helper_poll_init(&priv->drm);
>   
>   	platform_set_drvdata(pdev, priv);
>   
> -	ret = drm_dev_register(drm, 0);
> +	ret = drm_dev_register(&priv->drm, 0);
>   	if (ret)
>   		goto uninstall_irq;
>   
> -	drm_fbdev_dma_setup(drm, 32);
> +	drm_fbdev_dma_setup(&priv->drm, 32);
>   
>   	return 0;
>   
>   uninstall_irq:
> -	free_irq(priv->vsync_irq, drm);
> +	free_irq(priv->vsync_irq, &priv->drm);
>   exit_afbcd:
>   	if (priv->afbcd.ops)
>   		priv->afbcd.ops->exit(priv);
> @@ -370,15 +365,14 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
>   	meson_canvas_free(priv->canvas, priv->canvas_id_vd1_0);
>   free_canvas_osd1:
>   	meson_canvas_free(priv->canvas, priv->canvas_id_osd1);
> -free_drm:
> -	drm_dev_put(drm);
> +remove_encoders:
>   
>   	meson_encoder_dsi_remove(priv);
>   	meson_encoder_hdmi_remove(priv);
>   	meson_encoder_cvbs_remove(priv);
>   
>   	if (has_components)
> -		component_unbind_all(dev, drm);
> +		component_unbind_all(dev, &priv->drm);
>   
>   	return ret;
>   }
> @@ -391,7 +385,7 @@ static int meson_drv_bind(struct device *dev)
>   static void meson_drv_unbind(struct device *dev)
>   {
>   	struct meson_drm *priv = dev_get_drvdata(dev);
> -	struct drm_device *drm = priv->drm;
> +	struct drm_device *drm = &priv->drm;
>   
>   	if (priv->canvas) {
>   		meson_canvas_free(priv->canvas, priv->canvas_id_osd1);
> @@ -404,7 +398,6 @@ static void meson_drv_unbind(struct device *dev)
>   	drm_kms_helper_poll_fini(drm);
>   	drm_atomic_helper_shutdown(drm);
>   	free_irq(priv->vsync_irq, drm);
> -	drm_dev_put(drm);
>   
>   	meson_encoder_dsi_remove(priv);
>   	meson_encoder_hdmi_remove(priv);
> @@ -428,7 +421,7 @@ static int __maybe_unused meson_drv_pm_suspend(struct device *dev)
>   	if (!priv)
>   		return 0;
>   
> -	return drm_mode_config_helper_suspend(priv->drm);
> +	return drm_mode_config_helper_suspend(&priv->drm);
>   }
>   
>   static int __maybe_unused meson_drv_pm_resume(struct device *dev)
> @@ -445,7 +438,7 @@ static int __maybe_unused meson_drv_pm_resume(struct device *dev)
>   	if (priv->afbcd.ops)
>   		priv->afbcd.ops->init(priv);
>   
> -	return drm_mode_config_helper_resume(priv->drm);
> +	return drm_mode_config_helper_resume(&priv->drm);
>   }
>   
>   static void meson_drv_shutdown(struct platform_device *pdev)
> @@ -455,8 +448,8 @@ static void meson_drv_shutdown(struct platform_device *pdev)
>   	if (!priv)
>   		return;
>   
> -	drm_kms_helper_poll_fini(priv->drm);
> -	drm_atomic_helper_shutdown(priv->drm);
> +	drm_kms_helper_poll_fini(&priv->drm);
> +	drm_atomic_helper_shutdown(&priv->drm);
>   }
>   
>   /*
> diff --git a/drivers/gpu/drm/meson/meson_drv.h b/drivers/gpu/drm/meson/meson_drv.h
> index 3f9345c14f31..c4c6c810cb20 100644
> --- a/drivers/gpu/drm/meson/meson_drv.h
> +++ b/drivers/gpu/drm/meson/meson_drv.h
> @@ -53,7 +53,7 @@ struct meson_drm {
>   	u8 canvas_id_vd1_1;
>   	u8 canvas_id_vd1_2;
>   
> -	struct drm_device *drm;
> +	struct drm_device drm;
>   	struct drm_crtc *crtc;
>   	struct drm_plane *primary_plane;
>   	struct drm_plane *overlay_plane;
> diff --git a/drivers/gpu/drm/meson/meson_encoder_cvbs.c b/drivers/gpu/drm/meson/meson_encoder_cvbs.c
> index d1191de855d9..ddca22c8c1ff 100644
> --- a/drivers/gpu/drm/meson/meson_encoder_cvbs.c
> +++ b/drivers/gpu/drm/meson/meson_encoder_cvbs.c
> @@ -104,7 +104,7 @@ static int meson_encoder_cvbs_get_modes(struct drm_bridge *bridge,
>   	for (i = 0; i < MESON_CVBS_MODES_COUNT; ++i) {
>   		struct meson_cvbs_mode *meson_mode = &meson_cvbs_modes[i];
>   
> -		mode = drm_mode_duplicate(priv->drm, &meson_mode->mode);
> +		mode = drm_mode_duplicate(&priv->drm, &meson_mode->mode);
>   		if (!mode) {
>   			dev_err(priv->dev, "Failed to create a new display mode\n");
>   			return 0;
> @@ -221,7 +221,7 @@ static const struct drm_bridge_funcs meson_encoder_cvbs_bridge_funcs = {
>   
>   int meson_encoder_cvbs_probe(struct meson_drm *priv)
>   {
> -	struct drm_device *drm = priv->drm;
> +	struct drm_device *drm = &priv->drm;
>   	struct meson_encoder_cvbs *meson_encoder_cvbs;
>   	struct drm_connector *connector;
>   	struct device_node *remote;
> @@ -256,7 +256,7 @@ int meson_encoder_cvbs_probe(struct meson_drm *priv)
>   	meson_encoder_cvbs->priv = priv;
>   
>   	/* Encoder */
> -	ret = drm_simple_encoder_init(priv->drm, &meson_encoder_cvbs->encoder,
> +	ret = drm_simple_encoder_init(&priv->drm, &meson_encoder_cvbs->encoder,
>   				      DRM_MODE_ENCODER_TVDAC);
>   	if (ret)
>   		return dev_err_probe(priv->dev, ret,
> @@ -273,7 +273,7 @@ int meson_encoder_cvbs_probe(struct meson_drm *priv)
>   	}
>   
>   	/* Initialize & attach Bridge Connector */
> -	connector = drm_bridge_connector_init(priv->drm, &meson_encoder_cvbs->encoder);
> +	connector = drm_bridge_connector_init(&priv->drm, &meson_encoder_cvbs->encoder);
>   	if (IS_ERR(connector))
>   		return dev_err_probe(priv->dev, PTR_ERR(connector),
>   				     "Unable to create CVBS bridge connector\n");
> diff --git a/drivers/gpu/drm/meson/meson_overlay.c b/drivers/gpu/drm/meson/meson_overlay.c
> index 7f98de38842b..60ee7f758723 100644
> --- a/drivers/gpu/drm/meson/meson_overlay.c
> +++ b/drivers/gpu/drm/meson/meson_overlay.c
> @@ -484,7 +484,7 @@ static void meson_overlay_atomic_update(struct drm_plane *plane,
>   
>   	interlace_mode = new_state->crtc->mode.flags & DRM_MODE_FLAG_INTERLACE;
>   
> -	spin_lock_irqsave(&priv->drm->event_lock, flags);
> +	spin_lock_irqsave(&priv->drm.event_lock, flags);
>   
>   	if ((fb->modifier & DRM_FORMAT_MOD_AMLOGIC_FBC(0, 0)) ==
>   			    DRM_FORMAT_MOD_AMLOGIC_FBC(0, 0)) {
> @@ -717,7 +717,7 @@ static void meson_overlay_atomic_update(struct drm_plane *plane,
>   
>   	priv->viu.vd1_enabled = true;
>   
> -	spin_unlock_irqrestore(&priv->drm->event_lock, flags);
> +	spin_unlock_irqrestore(&priv->drm.event_lock, flags);
>   
>   	DRM_DEBUG_DRIVER("\n");
>   }
> @@ -838,7 +838,7 @@ int meson_overlay_create(struct meson_drm *priv)
>   
>   	DRM_DEBUG_DRIVER("\n");
>   
> -	meson_overlay = devm_kzalloc(priv->drm->dev, sizeof(*meson_overlay),
> +	meson_overlay = devm_kzalloc(priv->drm.dev, sizeof(*meson_overlay),
>   				   GFP_KERNEL);
>   	if (!meson_overlay)
>   		return -ENOMEM;
> @@ -846,7 +846,7 @@ int meson_overlay_create(struct meson_drm *priv)
>   	meson_overlay->priv = priv;
>   	plane = &meson_overlay->base;
>   
> -	drm_universal_plane_init(priv->drm, plane, 0xFF,
> +	drm_universal_plane_init(&priv->drm, plane, 0xFF,
>   				 &meson_overlay_funcs,
>   				 supported_drm_formats,
>   				 ARRAY_SIZE(supported_drm_formats),
> diff --git a/drivers/gpu/drm/meson/meson_plane.c b/drivers/gpu/drm/meson/meson_plane.c
> index b43ac61201f3..13be94309bf4 100644
> --- a/drivers/gpu/drm/meson/meson_plane.c
> +++ b/drivers/gpu/drm/meson/meson_plane.c
> @@ -157,7 +157,7 @@ static void meson_plane_atomic_update(struct drm_plane *plane,
>   	 * Update Buffer
>   	 * Enable Plane
>   	 */
> -	spin_lock_irqsave(&priv->drm->event_lock, flags);
> +	spin_lock_irqsave(&priv->drm.event_lock, flags);
>   
>   	/* Check if AFBC decoder is required for this buffer */
>   	if ((meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM) ||
> @@ -393,7 +393,7 @@ static void meson_plane_atomic_update(struct drm_plane *plane,
>   
>   	priv->viu.osd1_enabled = true;
>   
> -	spin_unlock_irqrestore(&priv->drm->event_lock, flags);
> +	spin_unlock_irqrestore(&priv->drm.event_lock, flags);
>   }
>   
>   static void meson_plane_atomic_disable(struct drm_plane *plane,
> @@ -536,7 +536,7 @@ int meson_plane_create(struct meson_drm *priv)
>   	const uint64_t *format_modifiers = format_modifiers_default;
>   	int ret;
>   
> -	meson_plane = devm_kzalloc(priv->drm->dev, sizeof(*meson_plane),
> +	meson_plane = devm_kzalloc(priv->drm.dev, sizeof(*meson_plane),
>   				   GFP_KERNEL);
>   	if (!meson_plane)
>   		return -ENOMEM;
> @@ -549,14 +549,14 @@ int meson_plane_create(struct meson_drm *priv)
>   	else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A))
>   		format_modifiers = format_modifiers_afbc_g12a;
>   
> -	ret = drm_universal_plane_init(priv->drm, plane, 0xFF,
> +	ret = drm_universal_plane_init(&priv->drm, plane, 0xFF,
>   					&meson_plane_funcs,
>   					supported_drm_formats,
>   					ARRAY_SIZE(supported_drm_formats),
>   					format_modifiers,
>   					DRM_PLANE_TYPE_PRIMARY, "meson_primary_plane");
>   	if (ret) {
> -		devm_kfree(priv->drm->dev, meson_plane);
> +		devm_kfree(priv->drm.dev, meson_plane);
>   		return ret;
>   	}
>   

Re: [PATCH] drm/meson: switch to a managed drm device
Posted by Philipp Stanner 1 year, 3 months ago
On Wed, 2024-08-28 at 14:04 +0300, Anastasia Belova wrote:
> Switch to a managed drm device to cleanup some error handling
> and make future work easier.

It's best to state what the current situation is like and then how this
patch addresses it.

If the cleanup topic is separate from the addressed NULL pointer issue
referenced below, it might make sense to split it into two patches, one
that does the cleanup, and another that addresses the NULL pointer
deref.

> 
> Fix dereference of NULL in meson_drv_bind_master by removing
> drm_dev_put(drm) before meson_encoder_*_remove where drm
> dereferenced.

(-> "where drm *is* dereferenced" )

Can this be backported to older versions?

If yes, stable@vger.kernel.org should be put on CC.


> 
> Co-developed by Linux Verification Center (linuxtesting.org).
> 
> Signed-off-by: Anastasia Belova <abelova@astralinux.ru>

Should also include:

Cc: stable@vger.kernel.org # vX.Y
Fixes: <commit>

Спасибо,
P.

> ---
>  drivers/gpu/drm/meson/meson_crtc.c         | 10 +--
>  drivers/gpu/drm/meson/meson_drv.c          | 71 ++++++++++----------
> --
>  drivers/gpu/drm/meson/meson_drv.h          |  2 +-
>  drivers/gpu/drm/meson/meson_encoder_cvbs.c |  8 +--
>  drivers/gpu/drm/meson/meson_overlay.c      |  8 +--
>  drivers/gpu/drm/meson/meson_plane.c        | 10 +--
>  6 files changed, 51 insertions(+), 58 deletions(-)
> 
> diff --git a/drivers/gpu/drm/meson/meson_crtc.c
> b/drivers/gpu/drm/meson/meson_crtc.c
> index d70616da8ce2..e1c0bf3baeea 100644
> --- a/drivers/gpu/drm/meson/meson_crtc.c
> +++ b/drivers/gpu/drm/meson/meson_crtc.c
> @@ -662,13 +662,13 @@ void meson_crtc_irq(struct meson_drm *priv)
>  
>  	drm_crtc_handle_vblank(priv->crtc);
>  
> -	spin_lock_irqsave(&priv->drm->event_lock, flags);
> +	spin_lock_irqsave(&priv->drm.event_lock, flags);
>  	if (meson_crtc->event) {
>  		drm_crtc_send_vblank_event(priv->crtc, meson_crtc-
> >event);
>  		drm_crtc_vblank_put(priv->crtc);
>  		meson_crtc->event = NULL;
>  	}
> -	spin_unlock_irqrestore(&priv->drm->event_lock, flags);
> +	spin_unlock_irqrestore(&priv->drm.event_lock, flags);
>  }
>  
>  int meson_crtc_create(struct meson_drm *priv)
> @@ -677,18 +677,18 @@ int meson_crtc_create(struct meson_drm *priv)
>  	struct drm_crtc *crtc;
>  	int ret;
>  
> -	meson_crtc = devm_kzalloc(priv->drm->dev,
> sizeof(*meson_crtc),
> +	meson_crtc = devm_kzalloc(priv->drm.dev,
> sizeof(*meson_crtc),
>  				  GFP_KERNEL);
>  	if (!meson_crtc)
>  		return -ENOMEM;
>  
>  	meson_crtc->priv = priv;
>  	crtc = &meson_crtc->base;
> -	ret = drm_crtc_init_with_planes(priv->drm, crtc,
> +	ret = drm_crtc_init_with_planes(&priv->drm, crtc,
>  					priv->primary_plane, NULL,
>  					&meson_crtc_funcs,
> "meson_crtc");
>  	if (ret) {
> -		dev_err(priv->drm->dev, "Failed to init CRTC\n");
> +		dev_err(priv->drm.dev, "Failed to init CRTC\n");
>  		return ret;
>  	}
>  
> diff --git a/drivers/gpu/drm/meson/meson_drv.c
> b/drivers/gpu/drm/meson/meson_drv.c
> index 4bd0baa2a4f5..2e7c2e7c7b82 100644
> --- a/drivers/gpu/drm/meson/meson_drv.c
> +++ b/drivers/gpu/drm/meson/meson_drv.c
> @@ -182,7 +182,6 @@ static int meson_drv_bind_master(struct device
> *dev, bool has_components)
>  	struct platform_device *pdev = to_platform_device(dev);
>  	const struct meson_drm_match_data *match;
>  	struct meson_drm *priv;
> -	struct drm_device *drm;
>  	struct resource *res;
>  	void __iomem *regs;
>  	int ret, i;
> @@ -197,17 +196,13 @@ static int meson_drv_bind_master(struct device
> *dev, bool has_components)
>  	if (!match)
>  		return -ENODEV;
>  
> -	drm = drm_dev_alloc(&meson_driver, dev);
> -	if (IS_ERR(drm))
> -		return PTR_ERR(drm);
> +	priv = devm_drm_dev_alloc(dev, &meson_driver,
> +				 struct meson_drm, drm);
>  
> -	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> -	if (!priv) {
> -		ret = -ENOMEM;
> -		goto free_drm;
> -	}
> -	drm->dev_private = priv;
> -	priv->drm = drm;
> +	if (IS_ERR(priv))
> +		return PTR_ERR(priv);
> +
> +	priv->drm.dev_private = priv;
>  	priv->dev = dev;
>  	priv->compat = match->compat;
>  	priv->afbcd.ops = match->afbcd_ops;
> @@ -215,7 +210,7 @@ static int meson_drv_bind_master(struct device
> *dev, bool has_components)
>  	regs = devm_platform_ioremap_resource_byname(pdev, "vpu");
>  	if (IS_ERR(regs)) {
>  		ret = PTR_ERR(regs);
> -		goto free_drm;
> +		goto remove_encoders;
>  	}
>  
>  	priv->io_base = regs;
> @@ -223,13 +218,13 @@ static int meson_drv_bind_master(struct device
> *dev, bool has_components)
>  	res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
> "hhi");
>  	if (!res) {
>  		ret = -EINVAL;
> -		goto free_drm;
> +		goto remove_encoders;
>  	}
>  	/* Simply ioremap since it may be a shared register zone */
>  	regs = devm_ioremap(dev, res->start, resource_size(res));
>  	if (!regs) {
>  		ret = -EADDRNOTAVAIL;
> -		goto free_drm;
> +		goto remove_encoders;
>  	}
>  
>  	priv->hhi = devm_regmap_init_mmio(dev, regs,
> @@ -237,18 +232,18 @@ static int meson_drv_bind_master(struct device
> *dev, bool has_components)
>  	if (IS_ERR(priv->hhi)) {
>  		dev_err(&pdev->dev, "Couldn't create the HHI
> regmap\n");
>  		ret = PTR_ERR(priv->hhi);
> -		goto free_drm;
> +		goto remove_encoders;
>  	}
>  
>  	priv->canvas = meson_canvas_get(dev);
>  	if (IS_ERR(priv->canvas)) {
>  		ret = PTR_ERR(priv->canvas);
> -		goto free_drm;
> +		goto remove_encoders;
>  	}
>  
>  	ret = meson_canvas_alloc(priv->canvas, &priv-
> >canvas_id_osd1);
>  	if (ret)
> -		goto free_drm;
> +		goto remove_encoders;
>  	ret = meson_canvas_alloc(priv->canvas, &priv-
> >canvas_id_vd1_0);
>  	if (ret)
>  		goto free_canvas_osd1;
> @@ -261,7 +256,7 @@ static int meson_drv_bind_master(struct device
> *dev, bool has_components)
>  
>  	priv->vsync_irq = platform_get_irq(pdev, 0);
>  
> -	ret = drm_vblank_init(drm, 1);
> +	ret = drm_vblank_init(&priv->drm, 1);
>  	if (ret)
>  		goto free_canvas_vd1_2;
>  
> @@ -284,10 +279,10 @@ static int meson_drv_bind_master(struct device
> *dev, bool has_components)
>  	ret = drmm_mode_config_init(drm);
>  	if (ret)
>  		goto free_canvas_vd1_2;
> -	drm->mode_config.max_width = 3840;
> -	drm->mode_config.max_height = 2160;
> -	drm->mode_config.funcs = &meson_mode_config_funcs;
> -	drm->mode_config.helper_private	=
> &meson_mode_config_helpers;
> +	priv->drm.mode_config.max_width = 3840;
> +	priv->drm.mode_config.max_height = 2160;
> +	priv->drm.mode_config.funcs = &meson_mode_config_funcs;
> +	priv->drm.mode_config.helper_private =
> &meson_mode_config_helpers;
>  
>  	/* Hardware Initialization */
>  
> @@ -308,9 +303,9 @@ static int meson_drv_bind_master(struct device
> *dev, bool has_components)
>  		goto exit_afbcd;
>  
>  	if (has_components) {
> -		ret = component_bind_all(dev, drm);
> +		ret = component_bind_all(dev, &priv->drm);
>  		if (ret) {
> -			dev_err(drm->dev, "Couldn't bind all
> components\n");
> +			dev_err(priv->drm.dev, "Couldn't bind all
> components\n");
>  			/* Do not try to unbind */
>  			has_components = false;
>  			goto exit_afbcd;
> @@ -339,26 +334,26 @@ static int meson_drv_bind_master(struct device
> *dev, bool has_components)
>  	if (ret)
>  		goto exit_afbcd;
>  
> -	ret = request_irq(priv->vsync_irq, meson_irq, 0, drm-
> >driver->name, drm);
> +	ret = request_irq(priv->vsync_irq, meson_irq, 0, priv-
> >drm.driver->name, &priv->drm);
>  	if (ret)
>  		goto exit_afbcd;
>  
> -	drm_mode_config_reset(drm);
> +	drm_mode_config_reset(&priv->drm);
>  
> -	drm_kms_helper_poll_init(drm);
> +	drm_kms_helper_poll_init(&priv->drm);
>  
>  	platform_set_drvdata(pdev, priv);
>  
> -	ret = drm_dev_register(drm, 0);
> +	ret = drm_dev_register(&priv->drm, 0);
>  	if (ret)
>  		goto uninstall_irq;
>  
> -	drm_fbdev_dma_setup(drm, 32);
> +	drm_fbdev_dma_setup(&priv->drm, 32);
>  
>  	return 0;
>  
>  uninstall_irq:
> -	free_irq(priv->vsync_irq, drm);
> +	free_irq(priv->vsync_irq, &priv->drm);
>  exit_afbcd:
>  	if (priv->afbcd.ops)
>  		priv->afbcd.ops->exit(priv);
> @@ -370,15 +365,14 @@ static int meson_drv_bind_master(struct device
> *dev, bool has_components)
>  	meson_canvas_free(priv->canvas, priv->canvas_id_vd1_0);
>  free_canvas_osd1:
>  	meson_canvas_free(priv->canvas, priv->canvas_id_osd1);
> -free_drm:
> -	drm_dev_put(drm);
> +remove_encoders:
>  
>  	meson_encoder_dsi_remove(priv);
>  	meson_encoder_hdmi_remove(priv);
>  	meson_encoder_cvbs_remove(priv);
>  
>  	if (has_components)
> -		component_unbind_all(dev, drm);
> +		component_unbind_all(dev, &priv->drm);
>  
>  	return ret;
>  }
> @@ -391,7 +385,7 @@ static int meson_drv_bind(struct device *dev)
>  static void meson_drv_unbind(struct device *dev)
>  {
>  	struct meson_drm *priv = dev_get_drvdata(dev);
> -	struct drm_device *drm = priv->drm;
> +	struct drm_device *drm = &priv->drm;
>  
>  	if (priv->canvas) {
>  		meson_canvas_free(priv->canvas, priv-
> >canvas_id_osd1);
> @@ -404,7 +398,6 @@ static void meson_drv_unbind(struct device *dev)
>  	drm_kms_helper_poll_fini(drm);
>  	drm_atomic_helper_shutdown(drm);
>  	free_irq(priv->vsync_irq, drm);
> -	drm_dev_put(drm);
>  
>  	meson_encoder_dsi_remove(priv);
>  	meson_encoder_hdmi_remove(priv);
> @@ -428,7 +421,7 @@ static int __maybe_unused
> meson_drv_pm_suspend(struct device *dev)
>  	if (!priv)
>  		return 0;
>  
> -	return drm_mode_config_helper_suspend(priv->drm);
> +	return drm_mode_config_helper_suspend(&priv->drm);
>  }
>  
>  static int __maybe_unused meson_drv_pm_resume(struct device *dev)
> @@ -445,7 +438,7 @@ static int __maybe_unused
> meson_drv_pm_resume(struct device *dev)
>  	if (priv->afbcd.ops)
>  		priv->afbcd.ops->init(priv);
>  
> -	return drm_mode_config_helper_resume(priv->drm);
> +	return drm_mode_config_helper_resume(&priv->drm);
>  }
>  
>  static void meson_drv_shutdown(struct platform_device *pdev)
> @@ -455,8 +448,8 @@ static void meson_drv_shutdown(struct
> platform_device *pdev)
>  	if (!priv)
>  		return;
>  
> -	drm_kms_helper_poll_fini(priv->drm);
> -	drm_atomic_helper_shutdown(priv->drm);
> +	drm_kms_helper_poll_fini(&priv->drm);
> +	drm_atomic_helper_shutdown(&priv->drm);
>  }
>  
>  /*
> diff --git a/drivers/gpu/drm/meson/meson_drv.h
> b/drivers/gpu/drm/meson/meson_drv.h
> index 3f9345c14f31..c4c6c810cb20 100644
> --- a/drivers/gpu/drm/meson/meson_drv.h
> +++ b/drivers/gpu/drm/meson/meson_drv.h
> @@ -53,7 +53,7 @@ struct meson_drm {
>  	u8 canvas_id_vd1_1;
>  	u8 canvas_id_vd1_2;
>  
> -	struct drm_device *drm;
> +	struct drm_device drm;
>  	struct drm_crtc *crtc;
>  	struct drm_plane *primary_plane;
>  	struct drm_plane *overlay_plane;
> diff --git a/drivers/gpu/drm/meson/meson_encoder_cvbs.c
> b/drivers/gpu/drm/meson/meson_encoder_cvbs.c
> index d1191de855d9..ddca22c8c1ff 100644
> --- a/drivers/gpu/drm/meson/meson_encoder_cvbs.c
> +++ b/drivers/gpu/drm/meson/meson_encoder_cvbs.c
> @@ -104,7 +104,7 @@ static int meson_encoder_cvbs_get_modes(struct
> drm_bridge *bridge,
>  	for (i = 0; i < MESON_CVBS_MODES_COUNT; ++i) {
>  		struct meson_cvbs_mode *meson_mode =
> &meson_cvbs_modes[i];
>  
> -		mode = drm_mode_duplicate(priv->drm, &meson_mode-
> >mode);
> +		mode = drm_mode_duplicate(&priv->drm, &meson_mode-
> >mode);
>  		if (!mode) {
>  			dev_err(priv->dev, "Failed to create a new
> display mode\n");
>  			return 0;
> @@ -221,7 +221,7 @@ static const struct drm_bridge_funcs
> meson_encoder_cvbs_bridge_funcs = {
>  
>  int meson_encoder_cvbs_probe(struct meson_drm *priv)
>  {
> -	struct drm_device *drm = priv->drm;
> +	struct drm_device *drm = &priv->drm;
>  	struct meson_encoder_cvbs *meson_encoder_cvbs;
>  	struct drm_connector *connector;
>  	struct device_node *remote;
> @@ -256,7 +256,7 @@ int meson_encoder_cvbs_probe(struct meson_drm
> *priv)
>  	meson_encoder_cvbs->priv = priv;
>  
>  	/* Encoder */
> -	ret = drm_simple_encoder_init(priv->drm,
> &meson_encoder_cvbs->encoder,
> +	ret = drm_simple_encoder_init(&priv->drm,
> &meson_encoder_cvbs->encoder,
>  				      DRM_MODE_ENCODER_TVDAC);
>  	if (ret)
>  		return dev_err_probe(priv->dev, ret,
> @@ -273,7 +273,7 @@ int meson_encoder_cvbs_probe(struct meson_drm
> *priv)
>  	}
>  
>  	/* Initialize & attach Bridge Connector */
> -	connector = drm_bridge_connector_init(priv->drm,
> &meson_encoder_cvbs->encoder);
> +	connector = drm_bridge_connector_init(&priv->drm,
> &meson_encoder_cvbs->encoder);
>  	if (IS_ERR(connector))
>  		return dev_err_probe(priv->dev, PTR_ERR(connector),
>  				     "Unable to create CVBS bridge
> connector\n");
> diff --git a/drivers/gpu/drm/meson/meson_overlay.c
> b/drivers/gpu/drm/meson/meson_overlay.c
> index 7f98de38842b..60ee7f758723 100644
> --- a/drivers/gpu/drm/meson/meson_overlay.c
> +++ b/drivers/gpu/drm/meson/meson_overlay.c
> @@ -484,7 +484,7 @@ static void meson_overlay_atomic_update(struct
> drm_plane *plane,
>  
>  	interlace_mode = new_state->crtc->mode.flags &
> DRM_MODE_FLAG_INTERLACE;
>  
> -	spin_lock_irqsave(&priv->drm->event_lock, flags);
> +	spin_lock_irqsave(&priv->drm.event_lock, flags);
>  
>  	if ((fb->modifier & DRM_FORMAT_MOD_AMLOGIC_FBC(0, 0)) ==
>  			    DRM_FORMAT_MOD_AMLOGIC_FBC(0, 0)) {
> @@ -717,7 +717,7 @@ static void meson_overlay_atomic_update(struct
> drm_plane *plane,
>  
>  	priv->viu.vd1_enabled = true;
>  
> -	spin_unlock_irqrestore(&priv->drm->event_lock, flags);
> +	spin_unlock_irqrestore(&priv->drm.event_lock, flags);
>  
>  	DRM_DEBUG_DRIVER("\n");
>  }
> @@ -838,7 +838,7 @@ int meson_overlay_create(struct meson_drm *priv)
>  
>  	DRM_DEBUG_DRIVER("\n");
>  
> -	meson_overlay = devm_kzalloc(priv->drm->dev,
> sizeof(*meson_overlay),
> +	meson_overlay = devm_kzalloc(priv->drm.dev,
> sizeof(*meson_overlay),
>  				   GFP_KERNEL);
>  	if (!meson_overlay)
>  		return -ENOMEM;
> @@ -846,7 +846,7 @@ int meson_overlay_create(struct meson_drm *priv)
>  	meson_overlay->priv = priv;
>  	plane = &meson_overlay->base;
>  
> -	drm_universal_plane_init(priv->drm, plane, 0xFF,
> +	drm_universal_plane_init(&priv->drm, plane, 0xFF,
>  				 &meson_overlay_funcs,
>  				 supported_drm_formats,
>  				 ARRAY_SIZE(supported_drm_formats),
> diff --git a/drivers/gpu/drm/meson/meson_plane.c
> b/drivers/gpu/drm/meson/meson_plane.c
> index b43ac61201f3..13be94309bf4 100644
> --- a/drivers/gpu/drm/meson/meson_plane.c
> +++ b/drivers/gpu/drm/meson/meson_plane.c
> @@ -157,7 +157,7 @@ static void meson_plane_atomic_update(struct
> drm_plane *plane,
>  	 * Update Buffer
>  	 * Enable Plane
>  	 */
> -	spin_lock_irqsave(&priv->drm->event_lock, flags);
> +	spin_lock_irqsave(&priv->drm.event_lock, flags);
>  
>  	/* Check if AFBC decoder is required for this buffer */
>  	if ((meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM) ||
> @@ -393,7 +393,7 @@ static void meson_plane_atomic_update(struct
> drm_plane *plane,
>  
>  	priv->viu.osd1_enabled = true;
>  
> -	spin_unlock_irqrestore(&priv->drm->event_lock, flags);
> +	spin_unlock_irqrestore(&priv->drm.event_lock, flags);
>  }
>  
>  static void meson_plane_atomic_disable(struct drm_plane *plane,
> @@ -536,7 +536,7 @@ int meson_plane_create(struct meson_drm *priv)
>  	const uint64_t *format_modifiers = format_modifiers_default;
>  	int ret;
>  
> -	meson_plane = devm_kzalloc(priv->drm->dev,
> sizeof(*meson_plane),
> +	meson_plane = devm_kzalloc(priv->drm.dev,
> sizeof(*meson_plane),
>  				   GFP_KERNEL);
>  	if (!meson_plane)
>  		return -ENOMEM;
> @@ -549,14 +549,14 @@ int meson_plane_create(struct meson_drm *priv)
>  	else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A))
>  		format_modifiers = format_modifiers_afbc_g12a;
>  
> -	ret = drm_universal_plane_init(priv->drm, plane, 0xFF,
> +	ret = drm_universal_plane_init(&priv->drm, plane, 0xFF,
>  					&meson_plane_funcs,
>  					supported_drm_formats,
>  					ARRAY_SIZE(supported_drm_for
> mats),
>  					format_modifiers,
>  					DRM_PLANE_TYPE_PRIMARY,
> "meson_primary_plane");
>  	if (ret) {
> -		devm_kfree(priv->drm->dev, meson_plane);
> +		devm_kfree(priv->drm.dev, meson_plane);
>  		return ret;
>  	}
>