The drm_encoder_cleanup() was missing both from the error path of dw_hdmi_rockchip_bind(). This caused a crash when slub_debug was enabled and we ended up deferring probe of HDMI at boot.
This call isn't needed from unbind() because if dw_hdmi_bind() returns no error then it takes over the job of freeing the encoder (in dw_hdmi_unbind).
Signed-off-by: Douglas Anderson dianders@chromium.org --- Changes in v2: None
drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c index 3d3cf2f8891e..88776aba984e 100644 --- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c @@ -293,7 +293,16 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master, drm_encoder_init(drm, encoder, &dw_hdmi_rockchip_encoder_funcs, DRM_MODE_ENCODER_TMDS, NULL);
- return dw_hdmi_bind(dev, master, data, encoder, iores, irq, plat_data); + ret = dw_hdmi_bind(dev, master, data, encoder, iores, irq, plat_data); + + /* + * If dw_hdmi_bind() fails we'll never call dw_hdmi_unbind(), + * which would have called the encoder cleanup. Do it manually. + */ + if (ret) + drm_encoder_cleanup(encoder); + + return ret; }
static void dw_hdmi_rockchip_unbind(struct device *dev, struct device *master,
The drm_encoder_cleanup() was missing both from the error path of dw_hdmi_imx_bind(). This caused a crash when slub_debug was enabled and we ended up deferring probe of HDMI at boot.
This call isn't needed from unbind() because if dw_hdmi_bind() returns no error then it takes over the job of freeing the encoder (in dw_hdmi_unbind).
Signed-off-by: Douglas Anderson dianders@chromium.org --- Changes in v2: - IMX patch new in v2
drivers/gpu/drm/imx/dw_hdmi-imx.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/imx/dw_hdmi-imx.c b/drivers/gpu/drm/imx/dw_hdmi-imx.c index 2a95d10e9d92..c69c3142819c 100644 --- a/drivers/gpu/drm/imx/dw_hdmi-imx.c +++ b/drivers/gpu/drm/imx/dw_hdmi-imx.c @@ -245,7 +245,16 @@ static int dw_hdmi_imx_bind(struct device *dev, struct device *master, drm_encoder_init(drm, encoder, &dw_hdmi_imx_encoder_funcs, DRM_MODE_ENCODER_TMDS, NULL);
- return dw_hdmi_bind(dev, master, data, encoder, iores, irq, plat_data); + ret = dw_hdmi_bind(dev, master, data, encoder, iores, irq, plat_data); + + /* + * If dw_hdmi_bind() fails we'll never call dw_hdmi_unbind(), + * which would have called the encoder cleanup. Do it manually. + */ + if (ret) + drm_encoder_cleanup(encoder); + + return ret; }
static void dw_hdmi_imx_unbind(struct device *dev, struct device *master,
Hi,
On Mon, Mar 7, 2016 at 2:00 PM, Douglas Anderson dianders@chromium.org wrote:
The drm_encoder_cleanup() was missing both from the error path of dw_hdmi_imx_bind(). This caused a crash when slub_debug was enabled and we ended up deferring probe of HDMI at boot.
This call isn't needed from unbind() because if dw_hdmi_bind() returns no error then it takes over the job of freeing the encoder (in dw_hdmi_unbind).
Signed-off-by: Douglas Anderson dianders@chromium.org
Changes in v2:
- IMX patch new in v2
drivers/gpu/drm/imx/dw_hdmi-imx.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-)
Mark picked up:
[PATCH v2 1/5] drm/rockchip: dw_hdmi: Call drm_encoder_cleanup() in error path [PATCH v2 3/5] drm/rockchip: vop: Fix vop crtc cleanup [PATCH v2 4/5] drm/rockchip: dw_hdmi: Don't call platform_set_drvdata()
...for Rockchip, as you can see at https://patchwork.kernel.org/patch/8523301/.
Does someone want to pick up: [PATCH v2 2/5] drm/imx: dw_hdmi: Call drm_encoder_cleanup() in error path [PATCH v2 5/5] drm/imx: dw_hdmi: Don't call platform_set_drvdata()
Thanks!
-Doug
Hi Doug,
Am Montag, den 28.03.2016, 08:14 -0700 schrieb Doug Anderson:
Hi,
On Mon, Mar 7, 2016 at 2:00 PM, Douglas Anderson dianders@chromium.org wrote:
The drm_encoder_cleanup() was missing both from the error path of dw_hdmi_imx_bind(). This caused a crash when slub_debug was enabled and we ended up deferring probe of HDMI at boot.
This call isn't needed from unbind() because if dw_hdmi_bind() returns no error then it takes over the job of freeing the encoder (in dw_hdmi_unbind).
Signed-off-by: Douglas Anderson dianders@chromium.org
Changes in v2:
- IMX patch new in v2
drivers/gpu/drm/imx/dw_hdmi-imx.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-)
Mark picked up:
[PATCH v2 1/5] drm/rockchip: dw_hdmi: Call drm_encoder_cleanup() in error path [PATCH v2 3/5] drm/rockchip: vop: Fix vop crtc cleanup [PATCH v2 4/5] drm/rockchip: dw_hdmi: Don't call platform_set_drvdata()
...for Rockchip, as you can see at https://patchwork.kernel.org/patch/8523301/.
Does someone want to pick up: [PATCH v2 2/5] drm/imx: dw_hdmi: Call drm_encoder_cleanup() in error path [PATCH v2 5/5] drm/imx: dw_hdmi: Don't call platform_set_drvdata()
Thanks!
Thank you for the reminder, both patches applied.
regards Philipp
This fixes a few problems in the vop crtc cleanup (handling error paths and cleanup upon exit):
* The vop_create_crtc() error path had an unsafe version of the iterator used for iterating over all planes (though it was destroying planes in the iterator so should have used the safe version)
* vop_destroy_crtc() - wasn't calling vop_plane_destroy(), which made slub_debug unhappy, at least if we ended up running this due to a deferred probe.
* In vop_create_crtc() if we were missing the "port" device tree node we would fail but not return an error (found by code inspection).
Fix these problems.
Signed-off-by: Douglas Anderson dianders@chromium.org --- Changes in v2: None
drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index fd370548d7d7..f86f797f10fd 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -1108,7 +1108,7 @@ static int vop_create_crtc(struct vop *vop) const struct vop_data *vop_data = vop->data; struct device *dev = vop->dev; struct drm_device *drm_dev = vop->drm_dev; - struct drm_plane *primary = NULL, *cursor = NULL, *plane; + struct drm_plane *primary = NULL, *cursor = NULL, *plane, *tmp; struct drm_crtc *crtc = &vop->crtc; struct device_node *port; int ret; @@ -1148,7 +1148,7 @@ static int vop_create_crtc(struct vop *vop) ret = drm_crtc_init_with_planes(drm_dev, crtc, primary, cursor, &vop_crtc_funcs, NULL); if (ret) - return ret; + goto err_cleanup_planes;
drm_crtc_helper_add(crtc, &vop_crtc_helper_funcs);
@@ -1181,6 +1181,7 @@ static int vop_create_crtc(struct vop *vop) if (!port) { DRM_ERROR("no port node found in %s\n", dev->of_node->full_name); + ret = -ENOENT; goto err_cleanup_crtc; }
@@ -1194,7 +1195,8 @@ static int vop_create_crtc(struct vop *vop) err_cleanup_crtc: drm_crtc_cleanup(crtc); err_cleanup_planes: - list_for_each_entry(plane, &drm_dev->mode_config.plane_list, head) + list_for_each_entry_safe(plane, tmp, &drm_dev->mode_config.plane_list, + head) drm_plane_cleanup(plane); return ret; } @@ -1202,9 +1204,28 @@ err_cleanup_planes: static void vop_destroy_crtc(struct vop *vop) { struct drm_crtc *crtc = &vop->crtc; + struct drm_device *drm_dev = vop->drm_dev; + struct drm_plane *plane, *tmp;
rockchip_unregister_crtc_funcs(crtc); of_node_put(crtc->port); + + /* + * We need to cleanup the planes now. Why? + * + * The planes are "&vop->win[i].base". That means the memory is + * all part of the big "struct vop" chunk of memory. That memory + * was devm allocated and associated with this component. We need to + * free it ourselves before vop_unbind() finishes. + */ + list_for_each_entry_safe(plane, tmp, &drm_dev->mode_config.plane_list, + head) + vop_plane_destroy(plane); + + /* + * Destroy CRTC after vop_plane_destroy() since vop_disable_plane() + * references the CRTC. + */ drm_crtc_cleanup(crtc); }
The Rockchip dw_hdmi driver just called platform_set_drvdata() to get your hopes up that maybe, somehow, you'd be able to retrieve the 'struct rockchip_hdmi' from a pointer to the 'struct device'. You can't. When we call dw_hdmi_bind() the main driver calls dev_set_drvdata(), which clobbers our setting.
Let's just remove the platform_set_drvdata() to avoid dashing people's hopes.
Signed-off-by: Douglas Anderson dianders@chromium.org --- Changes in v2: - Don't call platform_set_drvdata() new for v2.
drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 2 -- 1 file changed, 2 deletions(-)
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c index 88776aba984e..d5cfef75fc80 100644 --- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c @@ -271,8 +271,6 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master, if (!iores) return -ENXIO;
- platform_set_drvdata(pdev, hdmi); - encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node); /* * If we failed to find the CRTC(s) which this encoder is
The IMX dw_hdmi driver just called platform_set_drvdata() to get your hopes up that maybe, somehow, you'd be able to retrieve the 'struct imx_hdmi' from a pointer to the 'struct device'. You can't. When we call dw_hdmi_bind() the main driver calls dev_set_drvdata(), which clobbers our setting.
Let's just remove the platform_set_drvdata() to avoid dashing people's hopes.
Signed-off-by: Douglas Anderson dianders@chromium.org --- Changes in v2: - Don't call platform_set_drvdata() new for v2.
drivers/gpu/drm/imx/dw_hdmi-imx.c | 2 -- 1 file changed, 2 deletions(-)
diff --git a/drivers/gpu/drm/imx/dw_hdmi-imx.c b/drivers/gpu/drm/imx/dw_hdmi-imx.c index c69c3142819c..a24631fdf4ad 100644 --- a/drivers/gpu/drm/imx/dw_hdmi-imx.c +++ b/drivers/gpu/drm/imx/dw_hdmi-imx.c @@ -225,8 +225,6 @@ static int dw_hdmi_imx_bind(struct device *dev, struct device *master, if (!iores) return -ENXIO;
- platform_set_drvdata(pdev, hdmi); - encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node); /* * If we failed to find the CRTC(s) which this encoder is
On 2016年03月08日 06:00, Douglas Anderson wrote:
The drm_encoder_cleanup() was missing both from the error path of dw_hdmi_rockchip_bind(). This caused a crash when slub_debug was enabled and we ended up deferring probe of HDMI at boot.
This call isn't needed from unbind() because if dw_hdmi_bind() returns no error then it takes over the job of freeing the encoder (in dw_hdmi_unbind).
Signed-off-by: Douglas Anderson dianders@chromium.org
Hi Douglas
it seems has no doubt on these patch, and it works on my board, So I'd like to apply following three patches.
[PATCH v2 1/5] drm/rockchip: dw_hdmi: Call drm_encoder_cleanup() in error path [PATCH v2 3/5] drm/rockchip: vop: Fix vop crtc cleanup [PATCH v2 4/5] drm/rockchip: dw_hdmi: Don't call platform_set_drvdata()
Thanks for your fixes.
-- Mark Yao
dri-devel@lists.freedesktop.org