diff options
author | Daniel Vetter <daniel.vetter@ffwll.ch> | 2014-11-04 22:57:27 +0100 |
---|---|---|
committer | Daniel Vetter <daniel.vetter@ffwll.ch> | 2014-11-06 21:08:37 +0100 |
commit | 321ebf04dc7ab5c54d658f93db0ffe35277664ab (patch) | |
tree | 91fcbe2b49f701015e1fbbc8fb98800b1a297fa1 /drivers/gpu/drm/drm_plane_helper.c | |
parent | 3150c7d0c686ffee9e414ccce705c34ebcbf4e30 (diff) | |
download | lwn-321ebf04dc7ab5c54d658f93db0ffe35277664ab.tar.gz lwn-321ebf04dc7ab5c54d658f93db0ffe35277664ab.zip |
drm/atomic: Refcounting for plane_state->fb
So my original plan was that the drm core refcounts framebuffers like
with the legacy ioctls. But that doesn't work for a bunch of reasons:
- State objects might live longer than until the next fb change
happens for a plane. For example delayed cleanup work only happens
_after_ the pageflip ioctl has completed. So this definitely doesn't
work without the plane state holding its own references.
- The other issue is transition from legacy to atomic implementations,
where the driver works under a mix of both worlds. Which means
legacy paths might not properly update the ->fb pointer under
plane->state->fb. Which is a bit a problem when then someone comes
around and _does_ try to clean it up when it's long gone.
The second issue is just a bit a transition bug, since drivers should
update plane->state->fb in all the paths that aren't converted yet.
But a bit more robustness for the transition can't hurt - we pull
similar tricks with cleaning up the old fb in the transitional helpers
already.
The pattern for drivers that transition is
if (plane->state)
drm_atomic_set_fb_for_plane(plane->state, plane->fb);
inserted after the fb update has logically completed at the end of
->set_config (or ->set_base/mode_set if using the crtc helpers),
->page_flip, ->update_plane or any other entry point which updates
plane->fb.
v2: Update kerneldoc - copypasta fail.
v3: Fix spelling in the commit message (Sean).
Reviewed-by: Sean Paul <seanpaul@chromium.org>
Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
Diffstat (limited to 'drivers/gpu/drm/drm_plane_helper.c')
-rw-r--r-- | drivers/gpu/drm/drm_plane_helper.c | 14 |
1 files changed, 7 insertions, 7 deletions
diff --git a/drivers/gpu/drm/drm_plane_helper.c b/drivers/gpu/drm/drm_plane_helper.c index fa56bb5da6c3..d99c452b0563 100644 --- a/drivers/gpu/drm/drm_plane_helper.c +++ b/drivers/gpu/drm/drm_plane_helper.c @@ -27,7 +27,9 @@ #include <drm/drmP.h> #include <drm/drm_plane_helper.h> #include <drm/drm_rect.h> +#include <drm/drm_atomic.h> #include <drm/drm_crtc_helper.h> +#include <drm/drm_atomic_helper.h> #define SUBPIXEL_MASK 0xffff @@ -464,7 +466,7 @@ out: if (plane->funcs->atomic_destroy_state) plane->funcs->atomic_destroy_state(plane, plane_state); else - kfree(plane_state); + drm_atomic_helper_plane_destroy_state(plane, plane_state); } return ret; @@ -505,15 +507,14 @@ int drm_plane_helper_update(struct drm_plane *plane, struct drm_crtc *crtc, if (plane->funcs->atomic_duplicate_state) plane_state = plane->funcs->atomic_duplicate_state(plane); else if (plane->state) - plane_state = kmemdup(plane->state, sizeof(*plane_state), - GFP_KERNEL); + plane_state = drm_atomic_helper_plane_duplicate_state(plane); else plane_state = kzalloc(sizeof(*plane_state), GFP_KERNEL); if (!plane_state) return -ENOMEM; plane_state->crtc = crtc; - plane_state->fb = fb; + drm_atomic_set_fb_for_plane(plane_state, fb); plane_state->crtc_x = crtc_x; plane_state->crtc_y = crtc_y; plane_state->crtc_h = crtc_h; @@ -552,15 +553,14 @@ int drm_plane_helper_disable(struct drm_plane *plane) if (plane->funcs->atomic_duplicate_state) plane_state = plane->funcs->atomic_duplicate_state(plane); else if (plane->state) - plane_state = kmemdup(plane->state, sizeof(*plane_state), - GFP_KERNEL); + plane_state = drm_atomic_helper_plane_duplicate_state(plane); else plane_state = kzalloc(sizeof(*plane_state), GFP_KERNEL); if (!plane_state) return -ENOMEM; plane_state->crtc = NULL; - plane_state->fb = NULL; + drm_atomic_set_fb_for_plane(plane_state, NULL); return drm_plane_helper_commit(plane, plane_state, plane->fb); } |