FROMLIST: drm/rockchip: vop: Fix vop crtc cleanup
authorDouglas Anderson <dianders@chromium.org>
Mon, 7 Mar 2016 22:00:52 +0000 (14:00 -0800)
committerHuang, Tao <huangtao@rock-chips.com>
Wed, 30 Mar 2016 02:02:47 +0000 (10:02 +0800)
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.

(am from https://patchwork.kernel.org/patch/8523361/)

Change-Id: I3c00faca6e2fc10edc5b4576012ac28b6809a2f3
Signed-off-by: Douglas Anderson <dianders@chromium.org>
Signed-off-by: Mark Yao <mark.yao@rock-chips.com>
drivers/gpu/drm/rockchip/rockchip_drm_vop.c

index aad4fd5249ca0e0844357c79cf72a20e0aeb063e..64e1b5a8920d421c891257df4e66014f3ef3e22a 100644 (file)
@@ -1140,7 +1140,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;
@@ -1180,7 +1180,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);
 
@@ -1213,6 +1213,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;
        }
 
@@ -1226,7 +1227,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;
 }
@@ -1234,9 +1236,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);
 }