drm/omap: dss: Cleanup DSS ports on initialisation failure

[ Upstream commit 2a0a3ae17d ]

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@xs4all.nl>
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
Acked-by: Sam Ravnborg <sam@ravnborg.org>
Tested-by: Sebastian Reichel <sebastian.reichel@collabora.com>
Reviewed-by: Sebastian Reichel <sebastian.reichel@collabora.com>
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20200226112514.12455-22-laurent.pinchart@ideasonboard.com
Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
Laurent Pinchart
2020-02-26 13:24:41 +02:00
committed by Greg Kroah-Hartman
parent b4bca7b2a6
commit 0d5984ba93

View File

@@ -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)