| From c99fdb3f80589af8da49cbc090e6597ffca85c7c Mon Sep 17 00:00:00 2001 |
| From: Chris Wilson <chris@chris-wilson.co.uk> |
| Date: Fri, 14 Oct 2016 13:18:18 +0100 |
| Subject: [PATCH 041/299] drm: Add reference counting to drm_atomic_state |
| |
| drm_atomic_state has a complicated single owner model that tracks the |
| single reference from allocation through to destruction on another |
| thread - or perhaps on a local error path. We can simplify this tracking |
| by using reference counting (at a cost of a few more atomics). This is |
| even more beneficial when the lifetime of the state becomes more |
| convoluted than being passed to a single worker thread for the commit. |
| |
| v2: Double check !intel atomic_commit functions for missing gets |
| v3: Update kerneldocs |
| |
| Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> |
| Cc: Daniel Vetter <daniel.vetter@ffwll.ch> |
| Cc: dri-devel@lists.freedesktop.org |
| Reviewed-by: Eric Engestrom <eric.engestrom@imgtec.com> |
| Reviewed-by: Sean Paul <seanpaul@chromium.org> |
| Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch> |
| Link: http://patchwork.freedesktop.org/patch/msgid/20161014121833.439-27-chris@chris-wilson.co.uk |
| (cherry picked from commit 0853695c3ba46f97dfc0b5885f7b7e640ca212dd) |
| Signed-off-by: Simon Horman <horms+renesas@verge.net.au> |
| --- |
| drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c | 3 |
| drivers/gpu/drm/drm_atomic.c | 25 ++---- |
| drivers/gpu/drm/drm_atomic_helper.c | 98 ++++++--------------------- |
| drivers/gpu/drm/drm_fb_helper.c | 9 -- |
| drivers/gpu/drm/exynos/exynos_drm_drv.c | 3 |
| drivers/gpu/drm/i915/i915_debugfs.c | 5 - |
| drivers/gpu/drm/i915/intel_display.c | 31 ++++---- |
| drivers/gpu/drm/i915/intel_sprite.c | 4 - |
| drivers/gpu/drm/mediatek/mtk_drm_drv.c | 3 |
| drivers/gpu/drm/msm/msm_atomic.c | 3 |
| drivers/gpu/drm/omapdrm/omap_drv.c | 3 |
| drivers/gpu/drm/rcar-du/rcar_du_kms.c | 3 |
| drivers/gpu/drm/sti/sti_drv.c | 3 |
| drivers/gpu/drm/tegra/drm.c | 3 |
| drivers/gpu/drm/tilcdc/tilcdc_drv.c | 2 |
| drivers/gpu/drm/vc4/vc4_kms.c | 3 |
| include/drm/drm_atomic.h | 31 ++++++++ |
| include/drm/drm_plane.h | 1 |
| 18 files changed, 102 insertions(+), 131 deletions(-) |
| |
| --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c |
| +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c |
| @@ -464,7 +464,7 @@ atmel_hlcdc_dc_atomic_complete(struct at |
| |
| drm_atomic_helper_cleanup_planes(dev, old_state); |
| |
| - drm_atomic_state_free(old_state); |
| + drm_atomic_state_put(old_state); |
| |
| /* Complete the commit, wake up any waiter. */ |
| spin_lock(&dc->commit.wait.lock); |
| @@ -521,6 +521,7 @@ static int atmel_hlcdc_dc_atomic_commit( |
| /* Swap the state, this is the point of no return. */ |
| drm_atomic_helper_swap_state(state, true); |
| |
| + drm_atomic_state_get(state); |
| if (async) |
| queue_work(dc->wq, &commit->work); |
| else |
| --- a/drivers/gpu/drm/drm_atomic.c |
| +++ b/drivers/gpu/drm/drm_atomic.c |
| @@ -74,6 +74,8 @@ EXPORT_SYMBOL(drm_atomic_state_default_r |
| int |
| drm_atomic_state_init(struct drm_device *dev, struct drm_atomic_state *state) |
| { |
| + kref_init(&state->ref); |
| + |
| /* TODO legacy paths should maybe do a better job about |
| * setting this appropriately? |
| */ |
| @@ -215,22 +217,16 @@ void drm_atomic_state_clear(struct drm_a |
| EXPORT_SYMBOL(drm_atomic_state_clear); |
| |
| /** |
| - * drm_atomic_state_free - free all memory for an atomic state |
| - * @state: atomic state to deallocate |
| + * __drm_atomic_state_free - free all memory for an atomic state |
| + * @ref: This atomic state to deallocate |
| * |
| * This frees all memory associated with an atomic state, including all the |
| * per-object state for planes, crtcs and connectors. |
| */ |
| -void drm_atomic_state_free(struct drm_atomic_state *state) |
| +void __drm_atomic_state_free(struct kref *ref) |
| { |
| - struct drm_device *dev; |
| - struct drm_mode_config *config; |
| - |
| - if (!state) |
| - return; |
| - |
| - dev = state->dev; |
| - config = &dev->mode_config; |
| + struct drm_atomic_state *state = container_of(ref, typeof(*state), ref); |
| + struct drm_mode_config *config = &state->dev->mode_config; |
| |
| drm_atomic_state_clear(state); |
| |
| @@ -243,7 +239,7 @@ void drm_atomic_state_free(struct drm_at |
| kfree(state); |
| } |
| } |
| -EXPORT_SYMBOL(drm_atomic_state_free); |
| +EXPORT_SYMBOL(__drm_atomic_state_free); |
| |
| /** |
| * drm_atomic_get_crtc_state - get crtc state |
| @@ -1748,7 +1744,7 @@ retry: |
| if (arg->flags & DRM_MODE_ATOMIC_TEST_ONLY) { |
| /* |
| * Unlike commit, check_only does not clean up state. |
| - * Below we call drm_atomic_state_free for it. |
| + * Below we call drm_atomic_state_put for it. |
| */ |
| ret = drm_atomic_check_only(state); |
| } else if (arg->flags & DRM_MODE_ATOMIC_NONBLOCK) { |
| @@ -1781,8 +1777,7 @@ out: |
| goto retry; |
| } |
| |
| - if (ret || arg->flags & DRM_MODE_ATOMIC_TEST_ONLY) |
| - drm_atomic_state_free(state); |
| + drm_atomic_state_put(state); |
| |
| drm_modeset_drop_locks(&ctx); |
| drm_modeset_acquire_fini(&ctx); |
| --- a/drivers/gpu/drm/drm_atomic_helper.c |
| +++ b/drivers/gpu/drm/drm_atomic_helper.c |
| @@ -1203,7 +1203,7 @@ static void commit_tail(struct drm_atomi |
| |
| drm_atomic_helper_commit_cleanup_done(state); |
| |
| - drm_atomic_state_free(state); |
| + drm_atomic_state_put(state); |
| } |
| |
| static void commit_work(struct work_struct *work) |
| @@ -1287,6 +1287,7 @@ int drm_atomic_helper_commit(struct drm_ |
| * make sure work items don't artifically stall on each another. |
| */ |
| |
| + drm_atomic_state_get(state); |
| if (nonblock) |
| queue_work(system_unbound_wq, &state->commit_work); |
| else |
| @@ -1599,7 +1600,7 @@ EXPORT_SYMBOL(drm_atomic_helper_commit_h |
| * |
| * This signals completion of the atomic update @state, including any cleanup |
| * work. If used, it must be called right before calling |
| - * drm_atomic_state_free(). |
| + * drm_atomic_state_put(). |
| * |
| * This is part of the atomic helper support for nonblocking commits, see |
| * drm_atomic_helper_setup_commit() for an overview. |
| @@ -2122,18 +2123,13 @@ retry: |
| state->legacy_cursor_update = true; |
| |
| ret = drm_atomic_commit(state); |
| - if (ret != 0) |
| - goto fail; |
| - |
| - /* Driver takes ownership of state on successful commit. */ |
| - return 0; |
| fail: |
| if (ret == -EDEADLK) |
| goto backoff; |
| |
| - drm_atomic_state_free(state); |
| - |
| + drm_atomic_state_put(state); |
| return ret; |
| + |
| backoff: |
| drm_atomic_state_clear(state); |
| drm_atomic_legacy_backoff(state); |
| @@ -2195,18 +2191,13 @@ retry: |
| goto fail; |
| |
| ret = drm_atomic_commit(state); |
| - if (ret != 0) |
| - goto fail; |
| - |
| - /* Driver takes ownership of state on successful commit. */ |
| - return 0; |
| fail: |
| if (ret == -EDEADLK) |
| goto backoff; |
| |
| - drm_atomic_state_free(state); |
| - |
| + drm_atomic_state_put(state); |
| return ret; |
| + |
| backoff: |
| drm_atomic_state_clear(state); |
| drm_atomic_legacy_backoff(state); |
| @@ -2335,18 +2326,13 @@ retry: |
| goto fail; |
| |
| ret = drm_atomic_commit(state); |
| - if (ret != 0) |
| - goto fail; |
| - |
| - /* Driver takes ownership of state on successful commit. */ |
| - return 0; |
| fail: |
| if (ret == -EDEADLK) |
| goto backoff; |
| |
| - drm_atomic_state_free(state); |
| - |
| + drm_atomic_state_put(state); |
| return ret; |
| + |
| backoff: |
| drm_atomic_state_clear(state); |
| drm_atomic_legacy_backoff(state); |
| @@ -2488,11 +2474,8 @@ int drm_atomic_helper_disable_all(struct |
| } |
| |
| err = drm_atomic_commit(state); |
| - |
| free: |
| - if (err < 0) |
| - drm_atomic_state_free(state); |
| - |
| + drm_atomic_state_put(state); |
| return err; |
| } |
| EXPORT_SYMBOL(drm_atomic_helper_disable_all); |
| @@ -2543,7 +2526,7 @@ retry: |
| |
| err = drm_atomic_helper_disable_all(dev, &ctx); |
| if (err < 0) { |
| - drm_atomic_state_free(state); |
| + drm_atomic_state_put(state); |
| state = ERR_PTR(err); |
| goto unlock; |
| } |
| @@ -2632,18 +2615,13 @@ retry: |
| goto fail; |
| |
| ret = drm_atomic_commit(state); |
| - if (ret != 0) |
| - goto fail; |
| - |
| - /* Driver takes ownership of state on successful commit. */ |
| - return 0; |
| fail: |
| if (ret == -EDEADLK) |
| goto backoff; |
| |
| - drm_atomic_state_free(state); |
| - |
| + drm_atomic_state_put(state); |
| return ret; |
| + |
| backoff: |
| drm_atomic_state_clear(state); |
| drm_atomic_legacy_backoff(state); |
| @@ -2692,18 +2670,13 @@ retry: |
| goto fail; |
| |
| ret = drm_atomic_commit(state); |
| - if (ret != 0) |
| - goto fail; |
| - |
| - /* Driver takes ownership of state on successful commit. */ |
| - return 0; |
| fail: |
| if (ret == -EDEADLK) |
| goto backoff; |
| |
| - drm_atomic_state_free(state); |
| - |
| + drm_atomic_state_put(state); |
| return ret; |
| + |
| backoff: |
| drm_atomic_state_clear(state); |
| drm_atomic_legacy_backoff(state); |
| @@ -2752,18 +2725,13 @@ retry: |
| goto fail; |
| |
| ret = drm_atomic_commit(state); |
| - if (ret != 0) |
| - goto fail; |
| - |
| - /* Driver takes ownership of state on successful commit. */ |
| - return 0; |
| fail: |
| if (ret == -EDEADLK) |
| goto backoff; |
| |
| - drm_atomic_state_free(state); |
| - |
| + drm_atomic_state_put(state); |
| return ret; |
| + |
| backoff: |
| drm_atomic_state_clear(state); |
| drm_atomic_legacy_backoff(state); |
| @@ -2836,18 +2804,13 @@ retry: |
| } |
| |
| ret = drm_atomic_nonblocking_commit(state); |
| - if (ret != 0) |
| - goto fail; |
| - |
| - /* Driver takes ownership of state on successful commit. */ |
| - return 0; |
| fail: |
| if (ret == -EDEADLK) |
| goto backoff; |
| |
| - drm_atomic_state_free(state); |
| - |
| + drm_atomic_state_put(state); |
| return ret; |
| + |
| backoff: |
| drm_atomic_state_clear(state); |
| drm_atomic_legacy_backoff(state); |
| @@ -2923,19 +2886,14 @@ retry: |
| crtc_state->active = active; |
| |
| ret = drm_atomic_commit(state); |
| - if (ret != 0) |
| - goto fail; |
| - |
| - /* Driver takes ownership of state on successful commit. */ |
| - return 0; |
| fail: |
| if (ret == -EDEADLK) |
| goto backoff; |
| |
| connector->dpms = old_mode; |
| - drm_atomic_state_free(state); |
| - |
| + drm_atomic_state_put(state); |
| return ret; |
| + |
| backoff: |
| drm_atomic_state_clear(state); |
| drm_atomic_legacy_backoff(state); |
| @@ -3344,7 +3302,7 @@ drm_atomic_helper_duplicate_state(struct |
| |
| free: |
| if (err < 0) { |
| - drm_atomic_state_free(state); |
| + drm_atomic_state_put(state); |
| state = ERR_PTR(err); |
| } |
| |
| @@ -3459,22 +3417,14 @@ retry: |
| goto fail; |
| |
| ret = drm_atomic_commit(state); |
| - if (ret) |
| - goto fail; |
| - |
| - /* Driver takes ownership of state on successful commit. */ |
| - |
| - drm_property_unreference_blob(blob); |
| - |
| - return 0; |
| fail: |
| if (ret == -EDEADLK) |
| goto backoff; |
| |
| - drm_atomic_state_free(state); |
| + drm_atomic_state_put(state); |
| drm_property_unreference_blob(blob); |
| - |
| return ret; |
| + |
| backoff: |
| drm_atomic_state_clear(state); |
| drm_atomic_legacy_backoff(state); |
| --- a/drivers/gpu/drm/drm_fb_helper.c |
| +++ b/drivers/gpu/drm/drm_fb_helper.c |
| @@ -372,9 +372,7 @@ fail: |
| if (ret == -EDEADLK) |
| goto backoff; |
| |
| - if (ret != 0) |
| - drm_atomic_state_free(state); |
| - |
| + drm_atomic_state_put(state); |
| return ret; |
| |
| backoff: |
| @@ -1391,16 +1389,13 @@ retry: |
| info->var.xoffset = var->xoffset; |
| info->var.yoffset = var->yoffset; |
| |
| - |
| fail: |
| drm_atomic_clean_old_fb(dev, plane_mask, ret); |
| |
| if (ret == -EDEADLK) |
| goto backoff; |
| |
| - if (ret != 0) |
| - drm_atomic_state_free(state); |
| - |
| + drm_atomic_state_put(state); |
| return ret; |
| |
| backoff: |
| --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c |
| +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c |
| @@ -69,7 +69,7 @@ static void exynos_atomic_commit_complet |
| |
| drm_atomic_helper_cleanup_planes(dev, state); |
| |
| - drm_atomic_state_free(state); |
| + drm_atomic_state_put(state); |
| |
| spin_lock(&priv->lock); |
| priv->pending &= ~commit->crtcs; |
| @@ -254,6 +254,7 @@ int exynos_atomic_commit(struct drm_devi |
| |
| drm_atomic_helper_swap_state(state, true); |
| |
| + drm_atomic_state_get(state); |
| if (nonblock) |
| schedule_work(&commit->work); |
| else |
| --- a/drivers/gpu/drm/i915/i915_debugfs.c |
| +++ b/drivers/gpu/drm/i915/i915_debugfs.c |
| @@ -3941,10 +3941,9 @@ static void hsw_trans_edp_pipe_A_crc_wa( |
| |
| ret = drm_atomic_commit(state); |
| out: |
| - drm_modeset_unlock_all(dev); |
| WARN(ret, "Toggling workaround to %i returns %i\n", enable, ret); |
| - if (ret) |
| - drm_atomic_state_free(state); |
| + drm_modeset_unlock_all(dev); |
| + drm_atomic_state_put(state); |
| } |
| |
| static int ivb_pipe_crc_ctl_reg(struct drm_i915_private *dev_priv, |
| --- a/drivers/gpu/drm/i915/intel_display.c |
| +++ b/drivers/gpu/drm/i915/intel_display.c |
| @@ -3592,7 +3592,7 @@ void intel_prepare_reset(struct drm_i915 |
| return; |
| |
| err: |
| - drm_atomic_state_free(state); |
| + drm_atomic_state_put(state); |
| } |
| |
| void intel_finish_reset(struct drm_i915_private *dev_priv) |
| @@ -3654,6 +3654,8 @@ void intel_finish_reset(struct drm_i915_ |
| intel_hpd_init(dev_priv); |
| } |
| |
| + if (state) |
| + drm_atomic_state_put(state); |
| drm_modeset_drop_locks(ctx); |
| drm_modeset_acquire_fini(ctx); |
| mutex_unlock(&dev->mode_config.mutex); |
| @@ -6878,7 +6880,7 @@ static void intel_crtc_disable_noatomic( |
| |
| dev_priv->display.crtc_disable(crtc_state, state); |
| |
| - drm_atomic_state_free(state); |
| + drm_atomic_state_put(state); |
| |
| DRM_DEBUG_KMS("[CRTC:%d:%s] hw state adjusted, was enabled, now disabled\n", |
| crtc->base.id, crtc->name); |
| @@ -11286,8 +11288,8 @@ found: |
| return true; |
| |
| fail: |
| - drm_atomic_state_free(state); |
| - drm_atomic_state_free(restore_state); |
| + drm_atomic_state_put(state); |
| + drm_atomic_state_put(restore_state); |
| restore_state = state = NULL; |
| |
| if (ret == -EDEADLK) { |
| @@ -11316,10 +11318,9 @@ void intel_release_load_detect_pipe(stru |
| return; |
| |
| ret = drm_atomic_commit(state); |
| - if (ret) { |
| + if (ret) |
| DRM_DEBUG_KMS("Couldn't release load detect pipe: %i\n", ret); |
| - drm_atomic_state_free(state); |
| - } |
| + drm_atomic_state_put(state); |
| } |
| |
| static int i9xx_pll_refclk(struct drm_device *dev, |
| @@ -12388,8 +12389,7 @@ retry: |
| goto retry; |
| } |
| |
| - if (ret) |
| - drm_atomic_state_free(state); |
| + drm_atomic_state_put(state); |
| |
| if (ret == 0 && event) { |
| spin_lock_irq(&dev->event_lock); |
| @@ -14485,7 +14485,7 @@ static void intel_atomic_commit_tail(str |
| |
| drm_atomic_helper_commit_cleanup_done(state); |
| |
| - drm_atomic_state_free(state); |
| + drm_atomic_state_put(state); |
| |
| /* As one of the primary mmio accessors, KMS has a high likelihood |
| * of triggering bugs in unclaimed access. After we finish |
| @@ -14568,6 +14568,7 @@ static int intel_atomic_commit(struct dr |
| intel_shared_dpll_commit(state); |
| intel_atomic_track_fbs(state); |
| |
| + drm_atomic_state_get(state); |
| if (nonblock) |
| queue_work(system_unbound_wq, &state->commit_work); |
| else |
| @@ -14609,9 +14610,8 @@ retry: |
| goto retry; |
| } |
| |
| - if (ret) |
| out: |
| - drm_atomic_state_free(state); |
| + drm_atomic_state_put(state); |
| } |
| |
| /* |
| @@ -16353,8 +16353,8 @@ retry: |
| dev_priv->display.optimize_watermarks(cs); |
| } |
| |
| - drm_atomic_state_free(state); |
| fail: |
| + drm_atomic_state_put(state); |
| drm_modeset_drop_locks(&ctx); |
| drm_modeset_acquire_fini(&ctx); |
| } |
| @@ -16992,10 +16992,9 @@ void intel_display_resume(struct drm_dev |
| drm_modeset_acquire_fini(&ctx); |
| mutex_unlock(&dev->mode_config.mutex); |
| |
| - if (ret) { |
| + if (ret) |
| DRM_ERROR("Restoring old state failed with %i\n", ret); |
| - drm_atomic_state_free(state); |
| - } |
| + drm_atomic_state_put(state); |
| } |
| |
| void intel_modeset_gem_init(struct drm_device *dev) |
| --- a/drivers/gpu/drm/i915/intel_sprite.c |
| +++ b/drivers/gpu/drm/i915/intel_sprite.c |
| @@ -1008,9 +1008,7 @@ int intel_sprite_set_colorkey(struct drm |
| drm_modeset_backoff(&ctx); |
| } |
| |
| - if (ret) |
| - drm_atomic_state_free(state); |
| - |
| + drm_atomic_state_put(state); |
| out: |
| drm_modeset_drop_locks(&ctx); |
| drm_modeset_acquire_fini(&ctx); |
| --- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c |
| +++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c |
| @@ -83,7 +83,7 @@ static void mtk_atomic_complete(struct m |
| drm_atomic_helper_wait_for_vblanks(drm, state); |
| |
| drm_atomic_helper_cleanup_planes(drm, state); |
| - drm_atomic_state_free(state); |
| + drm_atomic_state_put(state); |
| } |
| |
| static void mtk_atomic_work(struct work_struct *work) |
| @@ -110,6 +110,7 @@ static int mtk_atomic_commit(struct drm_ |
| |
| drm_atomic_helper_swap_state(state, true); |
| |
| + drm_atomic_state_get(state); |
| if (async) |
| mtk_atomic_schedule(private, state); |
| else |
| --- a/drivers/gpu/drm/msm/msm_atomic.c |
| +++ b/drivers/gpu/drm/msm/msm_atomic.c |
| @@ -141,7 +141,7 @@ static void complete_commit(struct msm_c |
| |
| kms->funcs->complete_commit(kms, state); |
| |
| - drm_atomic_state_free(state); |
| + drm_atomic_state_put(state); |
| |
| commit_destroy(c); |
| } |
| @@ -256,6 +256,7 @@ int msm_atomic_commit(struct drm_device |
| * current layout. |
| */ |
| |
| + drm_atomic_state_get(state); |
| if (nonblock) { |
| queue_work(priv->atomic_wq, &c->work); |
| return 0; |
| --- a/drivers/gpu/drm/omapdrm/omap_drv.c |
| +++ b/drivers/gpu/drm/omapdrm/omap_drv.c |
| @@ -105,7 +105,7 @@ static void omap_atomic_complete(struct |
| |
| dispc_runtime_put(); |
| |
| - drm_atomic_state_free(old_state); |
| + drm_atomic_state_put(old_state); |
| |
| /* Complete the commit, wake up any waiter. */ |
| spin_lock(&priv->commit.lock); |
| @@ -176,6 +176,7 @@ static int omap_atomic_commit(struct drm |
| /* Swap the state, this is the point of no return. */ |
| drm_atomic_helper_swap_state(state, true); |
| |
| + drm_atomic_state_get(state); |
| if (nonblock) |
| schedule_work(&commit->work); |
| else |
| --- a/drivers/gpu/drm/rcar-du/rcar_du_kms.c |
| +++ b/drivers/gpu/drm/rcar-du/rcar_du_kms.c |
| @@ -272,7 +272,7 @@ static void rcar_du_atomic_complete(stru |
| |
| drm_atomic_helper_cleanup_planes(dev, old_state); |
| |
| - drm_atomic_state_free(old_state); |
| + drm_atomic_state_put(old_state); |
| |
| /* Complete the commit, wake up any waiter. */ |
| spin_lock(&rcdu->commit.wait.lock); |
| @@ -338,6 +338,7 @@ static int rcar_du_atomic_commit(struct |
| /* Swap the state, this is the point of no return. */ |
| drm_atomic_helper_swap_state(state, true); |
| |
| + drm_atomic_state_get(state); |
| if (nonblock) |
| schedule_work(&commit->work); |
| else |
| --- a/drivers/gpu/drm/sti/sti_drv.c |
| +++ b/drivers/gpu/drm/sti/sti_drv.c |
| @@ -184,7 +184,7 @@ static void sti_atomic_complete(struct s |
| drm_atomic_helper_wait_for_vblanks(drm, state); |
| |
| drm_atomic_helper_cleanup_planes(drm, state); |
| - drm_atomic_state_free(state); |
| + drm_atomic_state_put(state); |
| } |
| |
| static void sti_atomic_work(struct work_struct *work) |
| @@ -237,6 +237,7 @@ static int sti_atomic_commit(struct drm_ |
| |
| drm_atomic_helper_swap_state(state, true); |
| |
| + drm_atomic_state_get(state); |
| if (nonblock) |
| sti_atomic_schedule(private, state); |
| else |
| --- a/drivers/gpu/drm/tegra/drm.c |
| +++ b/drivers/gpu/drm/tegra/drm.c |
| @@ -63,7 +63,7 @@ static void tegra_atomic_complete(struct |
| drm_atomic_helper_wait_for_vblanks(drm, state); |
| |
| drm_atomic_helper_cleanup_planes(drm, state); |
| - drm_atomic_state_free(state); |
| + drm_atomic_state_put(state); |
| } |
| |
| static void tegra_atomic_work(struct work_struct *work) |
| @@ -96,6 +96,7 @@ static int tegra_atomic_commit(struct dr |
| |
| drm_atomic_helper_swap_state(state, true); |
| |
| + drm_atomic_state_get(state); |
| if (nonblock) |
| tegra_atomic_schedule(tegra, state); |
| else |
| --- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c |
| +++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c |
| @@ -143,8 +143,6 @@ static int tilcdc_commit(struct drm_devi |
| |
| drm_atomic_helper_cleanup_planes(dev, state); |
| |
| - drm_atomic_state_free(state); |
| - |
| return 0; |
| } |
| |
| --- a/drivers/gpu/drm/vc4/vc4_kms.c |
| +++ b/drivers/gpu/drm/vc4/vc4_kms.c |
| @@ -61,7 +61,7 @@ vc4_atomic_complete_commit(struct vc4_co |
| |
| drm_atomic_helper_cleanup_planes(dev, state); |
| |
| - drm_atomic_state_free(state); |
| + drm_atomic_state_put(state); |
| |
| up(&vc4->async_modeset); |
| |
| @@ -190,6 +190,7 @@ static int vc4_atomic_commit(struct drm_ |
| * current layout. |
| */ |
| |
| + drm_atomic_state_get(state); |
| if (nonblock) { |
| vc4_queue_seqno_cb(dev, &c->cb, wait_seqno, |
| vc4_atomic_complete_commit_seqno_cb); |
| --- a/include/drm/drm_atomic.h |
| +++ b/include/drm/drm_atomic.h |
| @@ -153,6 +153,7 @@ struct __drm_connnectors_state { |
| |
| /** |
| * struct drm_atomic_state - the global state object for atomic updates |
| + * @ref: count of all references to this state (will not be freed until zero) |
| * @dev: parent DRM device |
| * @allow_modeset: allow full modeset |
| * @legacy_cursor_update: hint to enforce legacy cursor IOCTL semantics |
| @@ -164,6 +165,8 @@ struct __drm_connnectors_state { |
| * @acquire_ctx: acquire context for this atomic modeset state update |
| */ |
| struct drm_atomic_state { |
| + struct kref ref; |
| + |
| struct drm_device *dev; |
| bool allow_modeset : 1; |
| bool legacy_cursor_update : 1; |
| @@ -193,7 +196,33 @@ static inline void drm_crtc_commit_get(s |
| struct drm_atomic_state * __must_check |
| drm_atomic_state_alloc(struct drm_device *dev); |
| void drm_atomic_state_clear(struct drm_atomic_state *state); |
| -void drm_atomic_state_free(struct drm_atomic_state *state); |
| + |
| +/** |
| + * drm_atomic_state_get - acquire a reference to the atomic state |
| + * @state: The atomic state |
| + * |
| + * Returns a new reference to the @state |
| + */ |
| +static inline struct drm_atomic_state * |
| +drm_atomic_state_get(struct drm_atomic_state *state) |
| +{ |
| + kref_get(&state->ref); |
| + return state; |
| +} |
| + |
| +void __drm_atomic_state_free(struct kref *ref); |
| + |
| +/** |
| + * drm_atomic_state_put - release a reference to the atomic state |
| + * @state: The atomic state |
| + * |
| + * This releases a reference to @state which is freed after removing the |
| + * final reference. No locking required and callable from any context. |
| + */ |
| +static inline void drm_atomic_state_put(struct drm_atomic_state *state) |
| +{ |
| + kref_put(&state->ref, __drm_atomic_state_free); |
| +} |
| |
| int __must_check |
| drm_atomic_state_init(struct drm_device *dev, struct drm_atomic_state *state); |
| --- a/include/drm/drm_plane.h |
| +++ b/include/drm/drm_plane.h |
| @@ -94,7 +94,6 @@ struct drm_plane_state { |
| struct drm_atomic_state *state; |
| }; |
| |
| - |
| /** |
| * struct drm_plane_funcs - driver plane control functions |
| */ |