From: Laurent Pinchart <laurent.pinchart@xxxxxxxxxxxxxxxx> [ Upstream commit 2a0a3ae17d36fa86dcf7c8e8d7b7f056ebd6c064 ] When the DSS initialises its output DPI and SDI ports, failures don't clean up previous successfully initialised ports. This can lead to resource leak or memory corruption. Fix it. Reported-by: Hans Verkuil <hverkuil@xxxxxxxxx> Signed-off-by: Laurent Pinchart <laurent.pinchart@xxxxxxxxxxxxxxxx> Reviewed-by: Tomi Valkeinen <tomi.valkeinen@xxxxxx> Acked-by: Sam Ravnborg <sam@xxxxxxxxxxxx> Tested-by: Sebastian Reichel <sebastian.reichel@xxxxxxxxxxxxx> Reviewed-by: Sebastian Reichel <sebastian.reichel@xxxxxxxxxxxxx> Signed-off-by: Tomi Valkeinen <tomi.valkeinen@xxxxxx> Link: https://patchwork.freedesktop.org/patch/msgid/20200226112514.12455-22-laurent.pinchart@xxxxxxxxxxxxxxxx Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx> --- drivers/gpu/drm/omapdrm/dss/dss.c | 43 +++++++++++++++++++------------ 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/omapdrm/dss/dss.c b/drivers/gpu/drm/omapdrm/dss/dss.c index 4bdd63b571002..ac93dae2a9c84 100644 --- a/drivers/gpu/drm/omapdrm/dss/dss.c +++ b/drivers/gpu/drm/omapdrm/dss/dss.c @@ -1151,46 +1151,38 @@ static const struct dss_features dra7xx_dss_feats = { .has_lcd_clk_src = true, }; -static int dss_init_ports(struct dss_device *dss) +static void __dss_uninit_ports(struct dss_device *dss, unsigned int num_ports) { struct platform_device *pdev = dss->pdev; struct device_node *parent = pdev->dev.of_node; struct device_node *port; unsigned int i; - int r; - for (i = 0; i < dss->feat->num_ports; i++) { + for (i = 0; i < num_ports; i++) { port = of_graph_get_port_by_id(parent, i); if (!port) continue; switch (dss->feat->ports[i]) { case OMAP_DISPLAY_TYPE_DPI: - r = dpi_init_port(dss, pdev, port, dss->feat->model); - if (r) - return r; + dpi_uninit_port(port); break; - case OMAP_DISPLAY_TYPE_SDI: - r = sdi_init_port(dss, pdev, port); - if (r) - return r; + sdi_uninit_port(port); break; - default: break; } } - - return 0; } -static void dss_uninit_ports(struct dss_device *dss) +static int dss_init_ports(struct dss_device *dss) { struct platform_device *pdev = dss->pdev; struct device_node *parent = pdev->dev.of_node; struct device_node *port; - int i; + unsigned int i; + int r; for (i = 0; i < dss->feat->num_ports; i++) { port = of_graph_get_port_by_id(parent, i); @@ -1199,15 +1191,32 @@ static void dss_uninit_ports(struct dss_device *dss) switch (dss->feat->ports[i]) { case OMAP_DISPLAY_TYPE_DPI: - dpi_uninit_port(port); + r = dpi_init_port(dss, pdev, port, dss->feat->model); + if (r) + goto error; break; + case OMAP_DISPLAY_TYPE_SDI: - sdi_uninit_port(port); + r = sdi_init_port(dss, pdev, port); + if (r) + goto error; break; + default: break; } } + + return 0; + +error: + __dss_uninit_ports(dss, i); + return r; +} + +static void dss_uninit_ports(struct dss_device *dss) +{ + __dss_uninit_ports(dss, dss->feat->num_ports); } static int dss_video_pll_probe(struct dss_device *dss) -- 2.25.1