Commit f002abc19acb6f7cdb3d320f3b6f1a565c0be63e
1 parent
dee8268f8f
Exists in
master
and in
16 other branches
drm/tegra: Properly cleanup and zero out resources
When the DRM driver is unloaded, all the associated resources must be cleaned up and zeroed out. This is necessary because of the architecture of the Tegra DRM driver, where not all subdrivers are unloaded along with the DRM driver. Therefore device-managed managed won't be freed and memory cannot be assumed to have been cleared (because it hasn't been reallocated using kzalloc()) by the time the DRM driver is reloaded. It is therefore necessary to zero out the structures to prevent strange errors (such as slab corruptions) from occurring. Signed-off-by: Thierry Reding <treding@nvidia.com>
Showing 3 changed files with 36 additions and 5 deletions Side-by-side Diff
drivers/gpu/drm/tegra/dc.c
... | ... | @@ -93,8 +93,11 @@ |
93 | 93 | |
94 | 94 | static void tegra_plane_destroy(struct drm_plane *plane) |
95 | 95 | { |
96 | + struct tegra_plane *p = to_tegra_plane(plane); | |
97 | + | |
96 | 98 | tegra_plane_disable(plane); |
97 | 99 | drm_plane_cleanup(plane); |
100 | + kfree(p); | |
98 | 101 | } |
99 | 102 | |
100 | 103 | static const struct drm_plane_funcs tegra_plane_funcs = { |
... | ... | @@ -120,7 +123,7 @@ |
120 | 123 | for (i = 0; i < 2; i++) { |
121 | 124 | struct tegra_plane *plane; |
122 | 125 | |
123 | - plane = devm_kzalloc(drm->dev, sizeof(*plane), GFP_KERNEL); | |
126 | + plane = kzalloc(sizeof(*plane), GFP_KERNEL); | |
124 | 127 | if (!plane) |
125 | 128 | return -ENOMEM; |
126 | 129 | |
127 | 130 | |
... | ... | @@ -129,8 +132,10 @@ |
129 | 132 | err = drm_plane_init(drm, &plane->base, 1 << dc->pipe, |
130 | 133 | &tegra_plane_funcs, plane_formats, |
131 | 134 | ARRAY_SIZE(plane_formats), false); |
132 | - if (err < 0) | |
135 | + if (err < 0) { | |
136 | + kfree(plane); | |
133 | 137 | return err; |
138 | + } | |
134 | 139 | } |
135 | 140 | |
136 | 141 | return 0; |
137 | 142 | |
138 | 143 | |
... | ... | @@ -251,14 +256,26 @@ |
251 | 256 | return 0; |
252 | 257 | } |
253 | 258 | |
259 | +static void drm_crtc_clear(struct drm_crtc *crtc) | |
260 | +{ | |
261 | + memset(crtc, 0, sizeof(*crtc)); | |
262 | +} | |
263 | + | |
264 | +static void tegra_dc_destroy(struct drm_crtc *crtc) | |
265 | +{ | |
266 | + drm_crtc_cleanup(crtc); | |
267 | + drm_crtc_clear(crtc); | |
268 | +} | |
269 | + | |
254 | 270 | static const struct drm_crtc_funcs tegra_crtc_funcs = { |
255 | 271 | .page_flip = tegra_dc_page_flip, |
256 | 272 | .set_config = drm_crtc_helper_set_config, |
257 | - .destroy = drm_crtc_cleanup, | |
273 | + .destroy = tegra_dc_destroy, | |
258 | 274 | }; |
259 | 275 | |
260 | 276 | static void tegra_crtc_disable(struct drm_crtc *crtc) |
261 | 277 | { |
278 | + struct tegra_dc *dc = to_tegra_dc(crtc); | |
262 | 279 | struct drm_device *drm = crtc->dev; |
263 | 280 | struct drm_plane *plane; |
264 | 281 | |
... | ... | @@ -273,6 +290,8 @@ |
273 | 290 | } |
274 | 291 | } |
275 | 292 | } |
293 | + | |
294 | + drm_vblank_off(drm, dc->pipe); | |
276 | 295 | } |
277 | 296 | |
278 | 297 | static bool tegra_crtc_mode_fixup(struct drm_crtc *crtc, |
drivers/gpu/drm/tegra/drm.c
... | ... | @@ -72,12 +72,12 @@ |
72 | 72 | |
73 | 73 | drm_kms_helper_poll_fini(drm); |
74 | 74 | tegra_drm_fb_exit(drm); |
75 | + drm_vblank_cleanup(drm); | |
76 | + drm_mode_config_cleanup(drm); | |
75 | 77 | |
76 | 78 | err = host1x_device_exit(device); |
77 | 79 | if (err < 0) |
78 | 80 | return err; |
79 | - | |
80 | - drm_mode_config_cleanup(drm); | |
81 | 81 | |
82 | 82 | return 0; |
83 | 83 | } |
drivers/gpu/drm/tegra/output.c
... | ... | @@ -79,10 +79,16 @@ |
79 | 79 | return status; |
80 | 80 | } |
81 | 81 | |
82 | +static void drm_connector_clear(struct drm_connector *connector) | |
83 | +{ | |
84 | + memset(connector, 0, sizeof(*connector)); | |
85 | +} | |
86 | + | |
82 | 87 | static void tegra_connector_destroy(struct drm_connector *connector) |
83 | 88 | { |
84 | 89 | drm_sysfs_connector_remove(connector); |
85 | 90 | drm_connector_cleanup(connector); |
91 | + drm_connector_clear(connector); | |
86 | 92 | } |
87 | 93 | |
88 | 94 | static const struct drm_connector_funcs connector_funcs = { |
89 | 95 | |
... | ... | @@ -92,9 +98,15 @@ |
92 | 98 | .destroy = tegra_connector_destroy, |
93 | 99 | }; |
94 | 100 | |
101 | +static void drm_encoder_clear(struct drm_encoder *encoder) | |
102 | +{ | |
103 | + memset(encoder, 0, sizeof(*encoder)); | |
104 | +} | |
105 | + | |
95 | 106 | static void tegra_encoder_destroy(struct drm_encoder *encoder) |
96 | 107 | { |
97 | 108 | drm_encoder_cleanup(encoder); |
109 | + drm_encoder_clear(encoder); | |
98 | 110 | } |
99 | 111 | |
100 | 112 | static const struct drm_encoder_funcs encoder_funcs = { |