drm/omap: dss: Cleanup DSS ports on initialisation failure
authorLaurent Pinchart <laurent.pinchart@ideasonboard.com>
Wed, 26 Feb 2020 11:24:41 +0000 (13:24 +0200)
committerTomi Valkeinen <tomi.valkeinen@ti.com>
Wed, 26 Feb 2020 11:31:44 +0000 (13:31 +0200)
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
drivers/gpu/drm/omapdrm/dss/dss.c

index 225ec808b01a980254afa72cd287286cca10bd44..67b92b5d8dd76da016841b142ac0ad9de7bf536b 100644 (file)
@@ -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)