From 0d5984ba936bb6e205d4c3a6bc7907d0526d437a Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 26 Feb 2020 13:24:41 +0200 Subject: [PATCH] drm/omap: dss: Cleanup DSS ports on initialisation failure [ 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 Signed-off-by: Laurent Pinchart Reviewed-by: Tomi Valkeinen Acked-by: Sam Ravnborg Tested-by: Sebastian Reichel Reviewed-by: Sebastian Reichel Signed-off-by: Tomi Valkeinen Link: https://patchwork.freedesktop.org/patch/msgid/20200226112514.12455-22-laurent.pinchart@ideasonboard.com Signed-off-by: Sasha Levin --- drivers/gpu/drm/omapdrm/dss/dss.c | 55 ++++++++++++++++++------------- 1 file changed, 32 insertions(+), 23 deletions(-) diff --git a/drivers/gpu/drm/omapdrm/dss/dss.c b/drivers/gpu/drm/omapdrm/dss/dss.c index 4bdd63b57100..ac93dae2a9c8 100644 --- a/drivers/gpu/drm/omapdrm/dss/dss.c +++ b/drivers/gpu/drm/omapdrm/dss/dss.c @@ -1151,6 +1151,31 @@ static const struct dss_features dra7xx_dss_feats = { .has_lcd_clk_src = true, }; +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; + + 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: + dpi_uninit_port(port); + break; + case OMAP_DISPLAY_TYPE_SDI: + sdi_uninit_port(port); + break; + default: + break; + } + } +} + static int dss_init_ports(struct dss_device *dss) { struct platform_device *pdev = dss->pdev; @@ -1168,13 +1193,13 @@ static int dss_init_ports(struct dss_device *dss) case OMAP_DISPLAY_TYPE_DPI: r = dpi_init_port(dss, pdev, port, dss->feat->model); if (r) - return r; + goto error; break; case OMAP_DISPLAY_TYPE_SDI: r = sdi_init_port(dss, pdev, port); if (r) - return r; + goto error; break; default: @@ -1183,31 +1208,15 @@ static int dss_init_ports(struct dss_device *dss) } return 0; + +error: + __dss_uninit_ports(dss, i); + return r; } static void dss_uninit_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; - - for (i = 0; i < dss->feat->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: - dpi_uninit_port(port); - break; - case OMAP_DISPLAY_TYPE_SDI: - sdi_uninit_port(port); - break; - default: - break; - } - } + __dss_uninit_ports(dss, dss->feat->num_ports); } static int dss_video_pll_probe(struct dss_device *dss)