diff options
author | Douglas Anderson <dianders@chromium.org> | 2016-03-07 17:00:52 -0500 |
---|---|---|
committer | Mark Yao <mark.yao@rock-chips.com> | 2016-03-28 02:48:32 -0400 |
commit | 328b51c0f5a07f3ee891ff012eb7f454be9d17c0 (patch) | |
tree | e80c90ed0aa607fb16da161091eab81f3a78e9be | |
parent | 948cf42700b15fc65ec4cc3ac52a8bbeb84b87ef (diff) |
drm/rockchip: vop: Fix vop crtc cleanup
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.
Signed-off-by: Douglas Anderson <dianders@chromium.org>
-rw-r--r-- | drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 27 |
1 files changed, 24 insertions, 3 deletions
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index 12854ac9d542..a619f120f801 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c | |||
@@ -1142,7 +1142,7 @@ static int vop_create_crtc(struct vop *vop) | |||
1142 | const struct vop_data *vop_data = vop->data; | 1142 | const struct vop_data *vop_data = vop->data; |
1143 | struct device *dev = vop->dev; | 1143 | struct device *dev = vop->dev; |
1144 | struct drm_device *drm_dev = vop->drm_dev; | 1144 | struct drm_device *drm_dev = vop->drm_dev; |
1145 | struct drm_plane *primary = NULL, *cursor = NULL, *plane; | 1145 | struct drm_plane *primary = NULL, *cursor = NULL, *plane, *tmp; |
1146 | struct drm_crtc *crtc = &vop->crtc; | 1146 | struct drm_crtc *crtc = &vop->crtc; |
1147 | struct device_node *port; | 1147 | struct device_node *port; |
1148 | int ret; | 1148 | int ret; |
@@ -1182,7 +1182,7 @@ static int vop_create_crtc(struct vop *vop) | |||
1182 | ret = drm_crtc_init_with_planes(drm_dev, crtc, primary, cursor, | 1182 | ret = drm_crtc_init_with_planes(drm_dev, crtc, primary, cursor, |
1183 | &vop_crtc_funcs, NULL); | 1183 | &vop_crtc_funcs, NULL); |
1184 | if (ret) | 1184 | if (ret) |
1185 | return ret; | 1185 | goto err_cleanup_planes; |
1186 | 1186 | ||
1187 | drm_crtc_helper_add(crtc, &vop_crtc_helper_funcs); | 1187 | drm_crtc_helper_add(crtc, &vop_crtc_helper_funcs); |
1188 | 1188 | ||
@@ -1215,6 +1215,7 @@ static int vop_create_crtc(struct vop *vop) | |||
1215 | if (!port) { | 1215 | if (!port) { |
1216 | DRM_ERROR("no port node found in %s\n", | 1216 | DRM_ERROR("no port node found in %s\n", |
1217 | dev->of_node->full_name); | 1217 | dev->of_node->full_name); |
1218 | ret = -ENOENT; | ||
1218 | goto err_cleanup_crtc; | 1219 | goto err_cleanup_crtc; |
1219 | } | 1220 | } |
1220 | 1221 | ||
@@ -1228,7 +1229,8 @@ static int vop_create_crtc(struct vop *vop) | |||
1228 | err_cleanup_crtc: | 1229 | err_cleanup_crtc: |
1229 | drm_crtc_cleanup(crtc); | 1230 | drm_crtc_cleanup(crtc); |
1230 | err_cleanup_planes: | 1231 | err_cleanup_planes: |
1231 | list_for_each_entry(plane, &drm_dev->mode_config.plane_list, head) | 1232 | list_for_each_entry_safe(plane, tmp, &drm_dev->mode_config.plane_list, |
1233 | head) | ||
1232 | drm_plane_cleanup(plane); | 1234 | drm_plane_cleanup(plane); |
1233 | return ret; | 1235 | return ret; |
1234 | } | 1236 | } |
@@ -1236,9 +1238,28 @@ err_cleanup_planes: | |||
1236 | static void vop_destroy_crtc(struct vop *vop) | 1238 | static void vop_destroy_crtc(struct vop *vop) |
1237 | { | 1239 | { |
1238 | struct drm_crtc *crtc = &vop->crtc; | 1240 | struct drm_crtc *crtc = &vop->crtc; |
1241 | struct drm_device *drm_dev = vop->drm_dev; | ||
1242 | struct drm_plane *plane, *tmp; | ||
1239 | 1243 | ||
1240 | rockchip_unregister_crtc_funcs(crtc); | 1244 | rockchip_unregister_crtc_funcs(crtc); |
1241 | of_node_put(crtc->port); | 1245 | of_node_put(crtc->port); |
1246 | |||
1247 | /* | ||
1248 | * We need to cleanup the planes now. Why? | ||
1249 | * | ||
1250 | * The planes are "&vop->win[i].base". That means the memory is | ||
1251 | * all part of the big "struct vop" chunk of memory. That memory | ||
1252 | * was devm allocated and associated with this component. We need to | ||
1253 | * free it ourselves before vop_unbind() finishes. | ||
1254 | */ | ||
1255 | list_for_each_entry_safe(plane, tmp, &drm_dev->mode_config.plane_list, | ||
1256 | head) | ||
1257 | vop_plane_destroy(plane); | ||
1258 | |||
1259 | /* | ||
1260 | * Destroy CRTC after vop_plane_destroy() since vop_disable_plane() | ||
1261 | * references the CRTC. | ||
1262 | */ | ||
1242 | drm_crtc_cleanup(crtc); | 1263 | drm_crtc_cleanup(crtc); |
1243 | } | 1264 | } |
1244 | 1265 | ||