diff options
author | Boris Brezillon <boris.brezillon@free-electrons.com> | 2015-10-10 07:55:39 +0200 |
---|---|---|
committer | Boris Brezillon <boris.brezillon@free-electrons.com> | 2016-04-14 09:17:24 +0200 |
commit | 1a7b37ca349bbdeb2f208a6a71a9925a716141f4 (patch) | |
tree | dbdd6c13ee02d8e473d7f64ffb14d3c496d4c628 /drivers/gpu/drm/atmel-hlcdc | |
parent | f9fd2adaacd8dc0ecbb38d96f3c62f20f0697176 (diff) |
drm: atmel-hlcdc: add a ->cleanup_fb() operation
Add a ->cleanup_fb() operation to avoid memory leaks when the atomic
operation is interrupted after the ->prepare_fb() call.
Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
Fixes 2389fc1 ("drm: atmel-hlcdc: Atomic mode-setting conversion")
Reviewed-by: Nicolas Ferre <nicolas.ferre@atmel.com>
Tested-by: Nicolas Ferre <nicolas.ferre@atmel.com>
Diffstat (limited to 'drivers/gpu/drm/atmel-hlcdc')
-rw-r--r-- | drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c | 52 |
1 files changed, 49 insertions, 3 deletions
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c index d65dcaee3832..2158d7a61c5e 100644 --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c @@ -37,6 +37,7 @@ * @xstride: value to add to the pixel pointer between each line * @pstride: value to add to the pixel pointer between each pixel * @nplanes: number of planes (deduced from pixel_format) + * @prepared: plane update has been prepared */ struct atmel_hlcdc_plane_state { struct drm_plane_state base; @@ -64,6 +65,7 @@ struct atmel_hlcdc_plane_state { int xstride[ATMEL_HLCDC_MAX_PLANES]; int pstride[ATMEL_HLCDC_MAX_PLANES]; int nplanes; + bool prepared; }; static inline struct atmel_hlcdc_plane_state * @@ -714,12 +716,54 @@ static int atmel_hlcdc_plane_atomic_check(struct drm_plane *p, static int atmel_hlcdc_plane_prepare_fb(struct drm_plane *p, const struct drm_plane_state *new_state) { + /* + * FIXME: we should avoid this const -> non-const cast but it's + * currently the only solution we have to modify the ->prepared + * state and rollback the update request. + * Ideally, we should rework the code to attach all the resources + * to atmel_hlcdc_plane_state (including the DMA desc allocation), + * but this require a complete rework of the atmel_hlcdc_layer + * code. + */ + struct drm_plane_state *s = (struct drm_plane_state *)new_state; struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p); + struct atmel_hlcdc_plane_state *state = + drm_plane_state_to_atmel_hlcdc_plane_state(s); + int ret; - if (!new_state->fb) - return 0; + ret = atmel_hlcdc_layer_update_start(&plane->layer); + if (!ret) + state->prepared = true; + + return ret; +} + +static void atmel_hlcdc_plane_cleanup_fb(struct drm_plane *p, + const struct drm_plane_state *old_state) +{ + /* + * FIXME: we should avoid this const -> non-const cast but it's + * currently the only solution we have to modify the ->prepared + * state and rollback the update request. + * Ideally, we should rework the code to attach all the resources + * to atmel_hlcdc_plane_state (including the DMA desc allocation), + * but this require a complete rework of the atmel_hlcdc_layer + * code. + */ + struct drm_plane_state *s = (struct drm_plane_state *)old_state; + struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p); + struct atmel_hlcdc_plane_state *state = + drm_plane_state_to_atmel_hlcdc_plane_state(s); + + /* + * The Request has already been applied or cancelled, nothing to do + * here. + */ + if (!state->prepared) + return; - return atmel_hlcdc_layer_update_start(&plane->layer); + atmel_hlcdc_layer_update_rollback(&plane->layer); + state->prepared = false; } static void atmel_hlcdc_plane_atomic_update(struct drm_plane *p, @@ -844,6 +888,7 @@ static void atmel_hlcdc_plane_init_properties(struct atmel_hlcdc_plane *plane, static struct drm_plane_helper_funcs atmel_hlcdc_layer_plane_helper_funcs = { .prepare_fb = atmel_hlcdc_plane_prepare_fb, + .cleanup_fb = atmel_hlcdc_plane_cleanup_fb, .atomic_check = atmel_hlcdc_plane_atomic_check, .atomic_update = atmel_hlcdc_plane_atomic_update, .atomic_disable = atmel_hlcdc_plane_atomic_disable, @@ -883,6 +928,7 @@ atmel_hlcdc_plane_atomic_duplicate_state(struct drm_plane *p) return NULL; copy->disc_updated = false; + copy->prepared = false; if (copy->base.fb) drm_framebuffer_reference(copy->base.fb); |