From: Ville Syrjälä ville.syrjala@linux.intel.com
OK, so here's the full version of my rw_semaphore GPU vs. display reset fix.
The only issue I'm aware of is that SKL watermark code still uses obj->state and thus I have no clue what would happen if one tries to run this on SKL. Untangling that would likely mean making the SKL wm code more in line with the g4x/vlv/chv code (ie. track things in the crtc state). I decided not to embark on that quest at this time.
Entire series available here: git://github.com/vsyrjala/linux.git reset_commit_rwsem_4
Ville Syrjälä (22): drm/i915: Pass the new crtc state to color management code drm/i915: Pass the crtc state explicitly to intel_pipe_update_start/end() drm/i915: Eliminate obj->state usage in g4x/vlv/chv wm computation drm/i915: Pass proper old/new states to intel_plane_atomic_check_with_state() drm/i915: Eliminate obj->state usage from pre/post plane update drm/i915: Eliminate crtc->state usage from intel_update_pipe_config() drm/i915: Eliminate crtc->state usage from intel_atomic_commit_tail and .crtc_update() drm: Add drm_dynarray drm/atomic: Convert state->connectors to drm_dynarray drm/atomic: Remove pointless private object NULL state check drm/atomic: Convert private_objs to drm_dynarray drm/atomic: Make private objs proper objects drm/atomic: Pass old state to __drm_atomic_helper_crtc_duplicate_state() & co. explicitly drm/arm: s/old_state/old_mali_state/ drm/mediatek: s/old_state/old_mtk_state/ drm/atomic: Pass old state explicitly to .atomic_duplicate_state() drm/atomic: Fix up the kernel docs for the state duplication functions drm: Return the connector from drm_connector_get() drm/i915% Store vma gtt offset in plane state drm/i915: Refactor __intel_atomic_commit_tail() drm/atomic: Introduce drm_atomic_helper_duplicate_commited_state() drm/i915: Solve the GPU reset vs. modeset deadlocks with an rw_semaphore
Documentation/gpu/drm-utils.rst | 15 ++ Documentation/gpu/index.rst | 1 + drivers/gpu/drm/Makefile | 2 +- drivers/gpu/drm/arm/malidp_crtc.c | 18 +- drivers/gpu/drm/arm/malidp_planes.c | 10 +- drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c | 10 +- drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c | 5 +- drivers/gpu/drm/drm_atomic.c | 174 +++++++----- drivers/gpu/drm/drm_atomic_helper.c | 318 ++++++++++++++++++++-- drivers/gpu/drm/drm_crtc_helper.c | 12 +- drivers/gpu/drm/drm_dp_mst_topology.c | 65 +++-- drivers/gpu/drm/drm_dynarray.c | 97 +++++++ drivers/gpu/drm/drm_fb_helper.c | 7 +- drivers/gpu/drm/drm_plane_helper.c | 12 +- drivers/gpu/drm/exynos/exynos_drm_plane.c | 8 +- drivers/gpu/drm/i915/i915_drv.h | 11 + drivers/gpu/drm/i915/intel_atomic.c | 16 +- drivers/gpu/drm/i915/intel_atomic_plane.c | 47 ++-- drivers/gpu/drm/i915/intel_display.c | 342 ++++++++++++++++-------- drivers/gpu/drm/i915/intel_drv.h | 52 +++- drivers/gpu/drm/i915/intel_pm.c | 30 +-- drivers/gpu/drm/i915/intel_sdvo.c | 9 +- drivers/gpu/drm/i915/intel_sprite.c | 37 +-- drivers/gpu/drm/imx/ipuv3-crtc.c | 6 +- drivers/gpu/drm/imx/ipuv3-plane.c | 8 +- drivers/gpu/drm/mediatek/mtk_drm_crtc.c | 6 +- drivers/gpu/drm/mediatek/mtk_drm_plane.c | 10 +- drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c | 10 +- drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c | 14 +- drivers/gpu/drm/nouveau/nouveau_connector.c | 8 +- drivers/gpu/drm/nouveau/nouveau_connector.h | 3 +- drivers/gpu/drm/nouveau/nv50_display.c | 16 +- drivers/gpu/drm/rcar-du/rcar_du_plane.c | 10 +- drivers/gpu/drm/rcar-du/rcar_du_vsp.c | 10 +- drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 6 +- drivers/gpu/drm/tegra/dc.c | 16 +- drivers/gpu/drm/tegra/dsi.c | 8 +- drivers/gpu/drm/tegra/sor.c | 8 +- drivers/gpu/drm/vc4/vc4_crtc.c | 6 +- drivers/gpu/drm/vc4/vc4_plane.c | 10 +- drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 26 +- drivers/gpu/drm/vmwgfx/vmwgfx_kms.h | 9 +- include/drm/drm_atomic.h | 179 ++++++++----- include/drm/drm_atomic_helper.h | 31 ++- include/drm/drm_connector.h | 23 +- include/drm/drm_crtc.h | 16 +- include/drm/drm_dp_mst_helper.h | 10 + include/drm/drm_dynarray.h | 54 ++++ include/drm/drm_plane.h | 16 +- 49 files changed, 1324 insertions(+), 493 deletions(-) create mode 100644 Documentation/gpu/drm-utils.rst create mode 100644 drivers/gpu/drm/drm_dynarray.c create mode 100644 include/drm/drm_dynarray.h
From: Ville Syrjälä ville.syrjala@linux.intel.com
In an effort to eliminate the obj->state usage let's pass on the new crtc state pointer (which we already have!) to the color management code.
Signed-off-by: Ville Syrjälä ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/intel_display.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 0648fd74be87..90fba8a44630 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -13546,8 +13546,8 @@ static void intel_begin_crtc_commit(struct drm_crtc *crtc, if (!modeset && (intel_cstate->base.color_mgmt_changed || intel_cstate->update_pipe)) { - intel_color_set_csc(crtc->state); - intel_color_load_luts(crtc->state); + intel_color_set_csc(&intel_cstate->base); + intel_color_load_luts(&intel_cstate->base); }
/* Perform vblank evasion around commit operation */
From: Ville Syrjälä ville.syrjala@linux.intel.com
Pass the appropriate new crtc state explicitly to intel_pipe_update_start/end() instead of of mucking around with crtc->state.
Signed-off-by: Ville Syrjälä ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/intel_display.c | 18 +++++++++++------- drivers/gpu/drm/i915/intel_drv.h | 13 +++++++++++-- drivers/gpu/drm/i915/intel_sprite.c | 28 ++++++++++++++-------------- 3 files changed, 36 insertions(+), 23 deletions(-)
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 90fba8a44630..cdfa95be4b8e 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -10645,7 +10645,7 @@ static void intel_mmio_flip_work_func(struct work_struct *w)
WARN_ON(i915_gem_object_wait(obj, 0, MAX_SCHEDULE_TIMEOUT, NULL) < 0);
- intel_pipe_update_start(crtc); + intel_pipe_update_start(crtc->config);
if (INTEL_GEN(dev_priv) >= 9) skl_do_mmio_flip(crtc, work->rotation, work); @@ -10653,7 +10653,7 @@ static void intel_mmio_flip_work_func(struct work_struct *w) /* use_mmio_flip() retricts MMIO flips to ilk+ */ ilk_do_mmio_flip(crtc, work);
- intel_pipe_update_end(crtc, work); + intel_pipe_update_end(crtc->config, work); }
static int intel_default_queue_flip(struct drm_device *dev, @@ -13535,13 +13535,13 @@ static void intel_begin_crtc_commit(struct drm_crtc *crtc, struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = to_i915(dev); struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - struct intel_crtc_state *intel_cstate = - to_intel_crtc_state(crtc->state); struct intel_crtc_state *old_intel_cstate = to_intel_crtc_state(old_crtc_state); struct intel_atomic_state *old_intel_state = to_intel_atomic_state(old_crtc_state->state); - bool modeset = needs_modeset(crtc->state); + struct intel_crtc_state *intel_cstate = + intel_atomic_get_new_crtc_state(old_intel_state, intel_crtc); + bool modeset = needs_modeset(&intel_cstate->base);
if (!modeset && (intel_cstate->base.color_mgmt_changed || @@ -13551,7 +13551,7 @@ static void intel_begin_crtc_commit(struct drm_crtc *crtc, }
/* Perform vblank evasion around commit operation */ - intel_pipe_update_start(intel_crtc); + intel_pipe_update_start(intel_cstate);
if (modeset) goto out; @@ -13571,8 +13571,12 @@ static void intel_finish_crtc_commit(struct drm_crtc *crtc, struct drm_crtc_state *old_crtc_state) { struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct intel_atomic_state *old_intel_state = + to_intel_atomic_state(old_crtc_state->state); + struct intel_crtc_state *new_crtc_state = + intel_atomic_get_new_crtc_state(old_intel_state, intel_crtc);
- intel_pipe_update_end(intel_crtc, NULL); + intel_pipe_update_end(new_crtc_state, NULL); }
/** diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index d17a32437f07..d22ca42f35da 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1207,6 +1207,14 @@ hdmi_to_dig_port(struct intel_hdmi *intel_hdmi) return container_of(intel_hdmi, struct intel_digital_port, hdmi); }
+static inline struct intel_crtc_state * +intel_atomic_get_new_crtc_state(struct intel_atomic_state *state, + struct intel_crtc *crtc) +{ + return to_intel_crtc_state(drm_atomic_get_new_crtc_state(&state->base, + &crtc->base)); +} + /* intel_fifo_underrun.c */ bool intel_set_cpu_fifo_underrun_reporting(struct drm_i915_private *dev_priv, enum pipe pipe, bool enable); @@ -1900,8 +1908,9 @@ struct intel_plane *intel_sprite_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe, int plane); int intel_sprite_set_colorkey(struct drm_device *dev, void *data, struct drm_file *file_priv); -void intel_pipe_update_start(struct intel_crtc *crtc); -void intel_pipe_update_end(struct intel_crtc *crtc, struct intel_flip_work *work); +void intel_pipe_update_start(const struct intel_crtc_state *new_crtc_state); +void intel_pipe_update_end(struct intel_crtc_state *new_crtc_state, + struct intel_flip_work *work);
/* intel_tv.c */ void intel_tv_init(struct drm_i915_private *dev_priv); diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index 0c650c2cbca8..697b95016c7a 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -69,8 +69,7 @@ int intel_usecs_to_scanlines(const struct drm_display_mode *adjusted_mode,
/** * intel_pipe_update_start() - start update of a set of display registers - * @crtc: the crtc of which the registers are going to be updated - * @start_vbl_count: vblank counter return pointer used for error checking + * @new_crtc_state: the new crtc state * * Mark the start of an update to pipe registers that should be updated * atomically regarding vblank. If the next vblank will happens within @@ -78,18 +77,18 @@ int intel_usecs_to_scanlines(const struct drm_display_mode *adjusted_mode, * * After a successful call to this function, interrupts will be disabled * until a subsequent call to intel_pipe_update_end(). That is done to - * avoid random delays. The value written to @start_vbl_count should be - * supplied to intel_pipe_update_end() for error checking. + * avoid random delays. */ -void intel_pipe_update_start(struct intel_crtc *crtc) +void intel_pipe_update_start(const struct intel_crtc_state *new_crtc_state) { + struct intel_crtc *crtc = to_intel_crtc(new_crtc_state->base.crtc); struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); - const struct drm_display_mode *adjusted_mode = &crtc->config->base.adjusted_mode; + const struct drm_display_mode *adjusted_mode = &new_crtc_state->base.adjusted_mode; long timeout = msecs_to_jiffies_timeout(1); int scanline, min, max, vblank_start; wait_queue_head_t *wq = drm_crtc_vblank_waitqueue(&crtc->base); bool need_vlv_dsi_wa = (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) && - intel_crtc_has_type(crtc->config, INTEL_OUTPUT_DSI); + intel_crtc_has_type(new_crtc_state, INTEL_OUTPUT_DSI); DEFINE_WAIT(wait);
vblank_start = adjusted_mode->crtc_vblank_start; @@ -169,15 +168,16 @@ void intel_pipe_update_start(struct intel_crtc *crtc)
/** * intel_pipe_update_end() - end update of a set of display registers - * @crtc: the crtc of which the registers were updated - * @start_vbl_count: start vblank counter (used for error checking) + * @new_crtc_state: the new crtc state * * Mark the end of an update started with intel_pipe_update_start(). This * re-enables interrupts and verifies the update was actually completed - * before a vblank using the value of @start_vbl_count. + * before a vblank. */ -void intel_pipe_update_end(struct intel_crtc *crtc, struct intel_flip_work *work) +void intel_pipe_update_end(struct intel_crtc_state *new_crtc_state, + struct intel_flip_work *work) { + struct intel_crtc *crtc = to_intel_crtc(new_crtc_state->base.crtc); enum pipe pipe = crtc->pipe; int scanline_end = intel_get_crtc_scanline(crtc); u32 end_vbl_count = intel_crtc_get_vblank_counter(crtc); @@ -196,14 +196,14 @@ void intel_pipe_update_end(struct intel_crtc *crtc, struct intel_flip_work *work * Would be slightly nice to just grab the vblank count and arm the * event outside of the critical section - the spinlock might spin for a * while ... */ - if (crtc->base.state->event) { + if (new_crtc_state->base.event) { WARN_ON(drm_crtc_vblank_get(&crtc->base) != 0);
spin_lock(&crtc->base.dev->event_lock); - drm_crtc_arm_vblank_event(&crtc->base, crtc->base.state->event); + drm_crtc_arm_vblank_event(&crtc->base, new_crtc_state->base.event); spin_unlock(&crtc->base.dev->event_lock);
- crtc->base.state->event = NULL; + new_crtc_state->base.event = NULL; }
local_irq_enable();
From: Ville Syrjälä ville.syrjala@linux.intel.com
Signed-off-by: Ville Syrjälä ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/i915_drv.h | 9 +++++++++ drivers/gpu/drm/i915/intel_drv.h | 8 ++++++++ drivers/gpu/drm/i915/intel_pm.c | 30 +++++++++++++++--------------- 3 files changed, 32 insertions(+), 15 deletions(-)
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 81cd21ecfa7d..baec61b078f5 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -563,6 +563,15 @@ struct i915_hotplug { (__i)++) \ for_each_if (plane_state)
+#define for_each_oldnew_intel_plane_in_state(__state, plane, old_plane_state, new_plane_state, __i) \ + for ((__i) = 0; \ + (__i) < (__state)->base.dev->mode_config.num_total_plane && \ + ((plane) = to_intel_plane((__state)->base.planes[__i].ptr), \ + (old_plane_state) = to_intel_plane_state((__state)->base.planes[__i].old_state), \ + (new_plane_state) = to_intel_plane_state((__state)->base.planes[__i].new_state), 1); \ + (__i)++) \ + for_each_if (plane) + struct drm_i915_private; struct i915_mm_struct; struct i915_mmu_object; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index d22ca42f35da..e9d61a03c46e 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1208,6 +1208,14 @@ hdmi_to_dig_port(struct intel_hdmi *intel_hdmi) }
static inline struct intel_crtc_state * +intel_atomic_get_old_crtc_state(struct intel_atomic_state *state, + struct intel_crtc *crtc) +{ + return to_intel_crtc_state(drm_atomic_get_old_crtc_state(&state->base, + &crtc->base)); +} + +static inline struct intel_crtc_state * intel_atomic_get_new_crtc_state(struct intel_atomic_state *state, struct intel_crtc *crtc) { diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index c3fcadfa0ae7..62320d70dc6f 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -1302,21 +1302,21 @@ static int g4x_compute_pipe_wm(struct intel_crtc_state *crtc_state) int num_active_planes = hweight32(crtc_state->active_planes & ~BIT(PLANE_CURSOR)); const struct g4x_pipe_wm *raw; - struct intel_plane_state *plane_state; + const struct intel_plane_state *old_plane_state; + const struct intel_plane_state *new_plane_state; struct intel_plane *plane; enum plane_id plane_id; int i, level; unsigned int dirty = 0;
- for_each_intel_plane_in_state(state, plane, plane_state, i) { - const struct intel_plane_state *old_plane_state = - to_intel_plane_state(plane->base.state); - - if (plane_state->base.crtc != &crtc->base && + for_each_oldnew_intel_plane_in_state(state, plane, + old_plane_state, + new_plane_state, i) { + if (new_plane_state->base.crtc != &crtc->base && old_plane_state->base.crtc != &crtc->base) continue;
- if (g4x_raw_plane_wm_compute(crtc_state, plane_state)) + if (g4x_raw_plane_wm_compute(crtc_state, new_plane_state)) dirty |= BIT(plane->id); }
@@ -1811,21 +1811,21 @@ static int vlv_compute_pipe_wm(struct intel_crtc_state *crtc_state) int num_active_planes = hweight32(crtc_state->active_planes & ~BIT(PLANE_CURSOR)); bool needs_modeset = drm_atomic_crtc_needs_modeset(&crtc_state->base); - struct intel_plane_state *plane_state; + const struct intel_plane_state *old_plane_state; + const struct intel_plane_state *new_plane_state; struct intel_plane *plane; enum plane_id plane_id; int level, ret, i; unsigned int dirty = 0;
- for_each_intel_plane_in_state(state, plane, plane_state, i) { - const struct intel_plane_state *old_plane_state = - to_intel_plane_state(plane->base.state); - - if (plane_state->base.crtc != &crtc->base && + for_each_oldnew_intel_plane_in_state(state, plane, + old_plane_state, + new_plane_state, i) { + if (new_plane_state->base.crtc != &crtc->base && old_plane_state->base.crtc != &crtc->base) continue;
- if (vlv_raw_plane_wm_compute(crtc_state, plane_state)) + if (vlv_raw_plane_wm_compute(crtc_state, new_plane_state)) dirty |= BIT(plane->id); }
@@ -1844,7 +1844,7 @@ static int vlv_compute_pipe_wm(struct intel_crtc_state *crtc_state) /* cursor changes don't warrant a FIFO recompute */ if (dirty & ~BIT(PLANE_CURSOR)) { const struct intel_crtc_state *old_crtc_state = - to_intel_crtc_state(crtc->base.state); + intel_atomic_get_old_crtc_state(state, crtc); const struct vlv_fifo_state *old_fifo_state = &old_crtc_state->wm.vlv.fifo_state;
From: Ville Syrjälä ville.syrjala@linux.intel.com
Eliminate plane->state and crtc->state usage from intel_plane_atomic_check_with_state() and its callers. Instead pass the proper states in or dig them up from the top level atomic state.
Note that intel_plane_atomic_check_with_state() itself isn't allowed to use the top level atomic state as there is none when it gets called from the legacy cursor short circuit path.
Signed-off-by: Ville Syrjälä ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/intel_atomic_plane.c | 40 +++++++++++++++++++------------ drivers/gpu/drm/i915/intel_display.c | 12 ++++++---- drivers/gpu/drm/i915/intel_drv.h | 16 +++++++++++-- 3 files changed, 46 insertions(+), 22 deletions(-)
diff --git a/drivers/gpu/drm/i915/intel_atomic_plane.c b/drivers/gpu/drm/i915/intel_atomic_plane.c index ee76fab7bb6f..7cdbe9ae2c96 100644 --- a/drivers/gpu/drm/i915/intel_atomic_plane.c +++ b/drivers/gpu/drm/i915/intel_atomic_plane.c @@ -107,7 +107,9 @@ intel_plane_destroy_state(struct drm_plane *plane, drm_atomic_helper_plane_destroy_state(plane, state); }
-int intel_plane_atomic_check_with_state(struct intel_crtc_state *crtc_state, +int intel_plane_atomic_check_with_state(const struct intel_crtc_state *old_crtc_state, + struct intel_crtc_state *crtc_state, + const struct intel_plane_state *old_plane_state, struct intel_plane_state *intel_state) { struct drm_plane *plane = intel_state->base.plane; @@ -124,7 +126,7 @@ int intel_plane_atomic_check_with_state(struct intel_crtc_state *crtc_state, * anything driver-specific we need to test in that case, so * just return success. */ - if (!intel_state->base.crtc && !plane->state->crtc) + if (!intel_state->base.crtc && !old_plane_state->base.crtc) return 0;
/* Clip all planes to CRTC size, or 0x0 if CRTC is disabled */ @@ -194,17 +196,21 @@ int intel_plane_atomic_check_with_state(struct intel_crtc_state *crtc_state, else crtc_state->active_planes &= ~BIT(intel_plane->id);
- return intel_plane_atomic_calc_changes(&crtc_state->base, state); + return intel_plane_atomic_calc_changes(old_crtc_state, + &crtc_state->base, + old_plane_state, + state); }
static int intel_plane_atomic_check(struct drm_plane *plane, struct drm_plane_state *state) { - struct drm_crtc *crtc = state->crtc; + const struct drm_plane_state *old_plane_state = + drm_atomic_get_old_plane_state(state->state, plane); + struct drm_crtc *crtc = state->crtc ?: old_plane_state->crtc; + const struct drm_crtc_state *old_crtc_state; struct drm_crtc_state *drm_crtc_state;
- crtc = crtc ? crtc : plane->state->crtc; - /* * Both crtc and plane->crtc could be NULL if we're updating a * property while the plane is disabled. We don't actually have @@ -214,29 +220,33 @@ static int intel_plane_atomic_check(struct drm_plane *plane, if (!crtc) return 0;
- drm_crtc_state = drm_atomic_get_existing_crtc_state(state->state, crtc); - if (WARN_ON(!drm_crtc_state)) - return -EINVAL; + old_crtc_state = drm_atomic_get_old_crtc_state(state->state, crtc); + drm_crtc_state = drm_atomic_get_new_crtc_state(state->state, crtc);
- return intel_plane_atomic_check_with_state(to_intel_crtc_state(drm_crtc_state), + return intel_plane_atomic_check_with_state(to_intel_crtc_state(old_crtc_state), + to_intel_crtc_state(drm_crtc_state), + to_intel_plane_state(old_plane_state), to_intel_plane_state(state)); }
static void intel_plane_atomic_update(struct drm_plane *plane, struct drm_plane_state *old_state) { + struct intel_atomic_state *state = to_intel_atomic_state(old_state->state); struct intel_plane *intel_plane = to_intel_plane(plane); - struct intel_plane_state *intel_state = - to_intel_plane_state(plane->state); - struct drm_crtc *crtc = plane->state->crtc ?: old_state->crtc; + const struct intel_plane_state *intel_state = + intel_atomic_get_new_plane_state(state, intel_plane); + struct drm_crtc *crtc = intel_state->base.crtc ?: old_state->crtc;
if (intel_state->base.visible) { + const struct intel_crtc_state *intel_crtc_state = + intel_atomic_get_new_crtc_state(state, to_intel_crtc(crtc)); + trace_intel_update_plane(plane, to_intel_crtc(crtc));
intel_plane->update_plane(intel_plane, - to_intel_crtc_state(crtc->state), - intel_state); + intel_crtc_state, intel_state); } else { trace_intel_disable_plane(plane, to_intel_crtc(crtc)); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index cdfa95be4b8e..6440479d6fe2 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -11011,7 +11011,7 @@ static bool intel_wm_need_update(struct drm_plane *plane, return false; }
-static bool needs_scaling(struct intel_plane_state *state) +static bool needs_scaling(const struct intel_plane_state *state) { int src_w = drm_rect_width(&state->base.src) >> 16; int src_h = drm_rect_height(&state->base.src) >> 16; @@ -11021,7 +11021,9 @@ static bool needs_scaling(struct intel_plane_state *state) return (src_w != dst_w || src_h != dst_h); }
-int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state, +int intel_plane_atomic_calc_changes(const struct intel_crtc_state *old_crtc_state, + struct drm_crtc_state *crtc_state, + const struct intel_plane_state *old_plane_state, struct drm_plane_state *plane_state) { struct intel_crtc_state *pipe_config = to_intel_crtc_state(crtc_state); @@ -11030,10 +11032,8 @@ int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state, struct intel_plane *plane = to_intel_plane(plane_state->plane); struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = to_i915(dev); - struct intel_plane_state *old_plane_state = - to_intel_plane_state(plane->base.state); bool mode_changed = needs_modeset(crtc_state); - bool was_crtc_enabled = crtc->state->active; + bool was_crtc_enabled = old_crtc_state->base.active; bool is_crtc_enabled = crtc_state->active; bool turn_off, turn_on, visible, was_visible; struct drm_framebuffer *fb = plane_state->fb; @@ -13660,6 +13660,8 @@ intel_legacy_cursor_update(struct drm_plane *plane, new_plane_state->crtc_h = crtc_h;
ret = intel_plane_atomic_check_with_state(to_intel_crtc_state(crtc->state), + to_intel_crtc_state(crtc->state), /* FIXME need a new crtc state? */ + to_intel_plane_state(plane->state), to_intel_plane_state(new_plane_state)); if (ret) goto out_free; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index e9d61a03c46e..ea36d1a61e86 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1207,6 +1207,14 @@ hdmi_to_dig_port(struct intel_hdmi *intel_hdmi) return container_of(intel_hdmi, struct intel_digital_port, hdmi); }
+static inline struct intel_plane_state * +intel_atomic_get_new_plane_state(struct intel_atomic_state *state, + struct intel_plane *plane) +{ + return to_intel_plane_state(drm_atomic_get_new_plane_state(&state->base, + &plane->base)); +} + static inline struct intel_crtc_state * intel_atomic_get_old_crtc_state(struct intel_atomic_state *state, struct intel_crtc *crtc) @@ -1439,7 +1447,9 @@ int intel_plane_atomic_set_property(struct drm_plane *plane, struct drm_plane_state *state, struct drm_property *property, uint64_t val); -int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state, +int intel_plane_atomic_calc_changes(const struct intel_crtc_state *old_crtc_state, + struct drm_crtc_state *crtc_state, + const struct intel_plane_state *old_plane_state, struct drm_plane_state *plane_state);
void assert_pch_transcoder_disabled(struct drm_i915_private *dev_priv, @@ -1990,7 +2000,9 @@ struct drm_plane_state *intel_plane_duplicate_state(struct drm_plane *plane); void intel_plane_destroy_state(struct drm_plane *plane, struct drm_plane_state *state); extern const struct drm_plane_helper_funcs intel_plane_helper_funcs; -int intel_plane_atomic_check_with_state(struct intel_crtc_state *crtc_state, +int intel_plane_atomic_check_with_state(const struct intel_crtc_state *old_crtc_state, + struct intel_crtc_state *crtc_state, + const struct intel_plane_state *old_plane_state, struct intel_plane_state *intel_state);
/* intel_color.c */
Op 06-07-17 om 22:24 schreef ville.syrjala@linux.intel.com:
From: Ville Syrjälä ville.syrjala@linux.intel.com
Eliminate plane->state and crtc->state usage from intel_plane_atomic_check_with_state() and its callers. Instead pass the proper states in or dig them up from the top level atomic state.
Note that intel_plane_atomic_check_with_state() itself isn't allowed to use the top level atomic state as there is none when it gets called from the legacy cursor short circuit path.
Signed-off-by: Ville Syrjälä ville.syrjala@linux.intel.com
drivers/gpu/drm/i915/intel_atomic_plane.c | 40 +++++++++++++++++++------------ drivers/gpu/drm/i915/intel_display.c | 12 ++++++---- drivers/gpu/drm/i915/intel_drv.h | 16 +++++++++++-- 3 files changed, 46 insertions(+), 22 deletions(-)
diff --git a/drivers/gpu/drm/i915/intel_atomic_plane.c b/drivers/gpu/drm/i915/intel_atomic_plane.c index ee76fab7bb6f..7cdbe9ae2c96 100644 --- a/drivers/gpu/drm/i915/intel_atomic_plane.c +++ b/drivers/gpu/drm/i915/intel_atomic_plane.c @@ -107,7 +107,9 @@ intel_plane_destroy_state(struct drm_plane *plane, drm_atomic_helper_plane_destroy_state(plane, state); }
-int intel_plane_atomic_check_with_state(struct intel_crtc_state *crtc_state, +int intel_plane_atomic_check_with_state(const struct intel_crtc_state *old_crtc_state,
struct intel_crtc_state *crtc_state,
const struct intel_plane_state *old_plane_state, struct intel_plane_state *intel_state)
{ struct drm_plane *plane = intel_state->base.plane; @@ -124,7 +126,7 @@ int intel_plane_atomic_check_with_state(struct intel_crtc_state *crtc_state, * anything driver-specific we need to test in that case, so * just return success. */
- if (!intel_state->base.crtc && !plane->state->crtc)
if (!intel_state->base.crtc && !old_plane_state->base.crtc) return 0;
/* Clip all planes to CRTC size, or 0x0 if CRTC is disabled */
@@ -194,17 +196,21 @@ int intel_plane_atomic_check_with_state(struct intel_crtc_state *crtc_state, else crtc_state->active_planes &= ~BIT(intel_plane->id);
- return intel_plane_atomic_calc_changes(&crtc_state->base, state);
- return intel_plane_atomic_calc_changes(old_crtc_state,
&crtc_state->base,
old_plane_state,
state);
}
static int intel_plane_atomic_check(struct drm_plane *plane, struct drm_plane_state *state)
new_plane_state?
{
- struct drm_crtc *crtc = state->crtc;
- const struct drm_plane_state *old_plane_state =
drm_atomic_get_old_plane_state(state->state, plane);
- struct drm_crtc *crtc = state->crtc ?: old_plane_state->crtc;
- const struct drm_crtc_state *old_crtc_state; struct drm_crtc_state *drm_crtc_state;
- crtc = crtc ? crtc : plane->state->crtc;
- /*
- Both crtc and plane->crtc could be NULL if we're updating a
- property while the plane is disabled. We don't actually have
@@ -214,29 +220,33 @@ static int intel_plane_atomic_check(struct drm_plane *plane, if (!crtc) return 0;
- drm_crtc_state = drm_atomic_get_existing_crtc_state(state->state, crtc);
- if (WARN_ON(!drm_crtc_state))
return -EINVAL;
- old_crtc_state = drm_atomic_get_old_crtc_state(state->state, crtc);
- drm_crtc_state = drm_atomic_get_new_crtc_state(state->state, crtc);
new_crtc_state?
- return intel_plane_atomic_check_with_state(to_intel_crtc_state(drm_crtc_state),
- return intel_plane_atomic_check_with_state(to_intel_crtc_state(old_crtc_state),
to_intel_crtc_state(drm_crtc_state),
to_intel_plane_state(old_plane_state), to_intel_plane_state(state));
}
static void intel_plane_atomic_update(struct drm_plane *plane, struct drm_plane_state *old_state) {
- struct intel_atomic_state *state = to_intel_atomic_state(old_state->state); struct intel_plane *intel_plane = to_intel_plane(plane);
- struct intel_plane_state *intel_state =
to_intel_plane_state(plane->state);
- struct drm_crtc *crtc = plane->state->crtc ?: old_state->crtc;
const struct intel_plane_state *intel_state =
intel_atomic_get_new_plane_state(state, intel_plane);
struct drm_crtc *crtc = intel_state->base.crtc ?: old_state->crtc;
if (intel_state->base.visible) {
const struct intel_crtc_state *intel_crtc_state =
intel_atomic_get_new_crtc_state(state, to_intel_crtc(crtc));
trace_intel_update_plane(plane, to_intel_crtc(crtc));
intel_plane->update_plane(intel_plane,
to_intel_crtc_state(crtc->state),
intel_state);
} else { trace_intel_disable_plane(plane, to_intel_crtc(crtc));intel_crtc_state, intel_state);
I think with so many names, might be better to use new_crtc_state and new_plane_state here.
State is used so much as keyword in atomic that with multiple states, intel_state becomes as descriptive as void *ptr. :)
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index cdfa95be4b8e..6440479d6fe2 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -11011,7 +11011,7 @@ static bool intel_wm_need_update(struct drm_plane *plane, return false; }
-static bool needs_scaling(struct intel_plane_state *state) +static bool needs_scaling(const struct intel_plane_state *state) { int src_w = drm_rect_width(&state->base.src) >> 16; int src_h = drm_rect_height(&state->base.src) >> 16; @@ -11021,7 +11021,9 @@ static bool needs_scaling(struct intel_plane_state *state) return (src_w != dst_w || src_h != dst_h); }
-int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state, +int intel_plane_atomic_calc_changes(const struct intel_crtc_state *old_crtc_state,
struct drm_crtc_state *crtc_state,
const struct intel_plane_state *old_plane_state, struct drm_plane_state *plane_state)
{ struct intel_crtc_state *pipe_config = to_intel_crtc_state(crtc_state); @@ -11030,10 +11032,8 @@ int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state, struct intel_plane *plane = to_intel_plane(plane_state->plane); struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = to_i915(dev);
- struct intel_plane_state *old_plane_state =
bool mode_changed = needs_modeset(crtc_state);to_intel_plane_state(plane->base.state);
- bool was_crtc_enabled = crtc->state->active;
- bool was_crtc_enabled = old_crtc_state->base.active; bool is_crtc_enabled = crtc_state->active; bool turn_off, turn_on, visible, was_visible; struct drm_framebuffer *fb = plane_state->fb;
@@ -13660,6 +13660,8 @@ intel_legacy_cursor_update(struct drm_plane *plane, new_plane_state->crtc_h = crtc_h;
ret = intel_plane_atomic_check_with_state(to_intel_crtc_state(crtc->state),
^old crtc state here?
to_intel_crtc_state(crtc->state), /* FIXME need a new crtc state? */
and crtc_state here? You already pass both to this function?
to_intel_plane_state(plane->state),
and old_plane_state here?
to_intel_plane_state(new_plane_state));
if (ret) goto out_free; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index e9d61a03c46e..ea36d1a61e86 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1207,6 +1207,14 @@ hdmi_to_dig_port(struct intel_hdmi *intel_hdmi) return container_of(intel_hdmi, struct intel_digital_port, hdmi); }
+static inline struct intel_plane_state * +intel_atomic_get_new_plane_state(struct intel_atomic_state *state,
struct intel_plane *plane)
+{
- return to_intel_plane_state(drm_atomic_get_new_plane_state(&state->base,
&plane->base));
+}
static inline struct intel_crtc_state * intel_atomic_get_old_crtc_state(struct intel_atomic_state *state, struct intel_crtc *crtc) @@ -1439,7 +1447,9 @@ int intel_plane_atomic_set_property(struct drm_plane *plane, struct drm_plane_state *state, struct drm_property *property, uint64_t val); -int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state, +int intel_plane_atomic_calc_changes(const struct intel_crtc_state *old_crtc_state,
struct drm_crtc_state *crtc_state,
const struct intel_plane_state *old_plane_state, struct drm_plane_state *plane_state);
void assert_pch_transcoder_disabled(struct drm_i915_private *dev_priv, @@ -1990,7 +2000,9 @@ struct drm_plane_state *intel_plane_duplicate_state(struct drm_plane *plane); void intel_plane_destroy_state(struct drm_plane *plane, struct drm_plane_state *state); extern const struct drm_plane_helper_funcs intel_plane_helper_funcs; -int intel_plane_atomic_check_with_state(struct intel_crtc_state *crtc_state, +int intel_plane_atomic_check_with_state(const struct intel_crtc_state *old_crtc_state,
struct intel_crtc_state *crtc_state,
const struct intel_plane_state *old_plane_state, struct intel_plane_state *intel_state);
/* intel_color.c */
Please for this whole patch, use old/new_plane/crtc_state, or it becomes unreadable very fast. :)
Idea looks good though, so looking forward to v2.
On Mon, Jul 10, 2017 at 11:04:31AM +0200, Maarten Lankhorst wrote:
Op 06-07-17 om 22:24 schreef ville.syrjala@linux.intel.com:
From: Ville Syrjälä ville.syrjala@linux.intel.com
Eliminate plane->state and crtc->state usage from intel_plane_atomic_check_with_state() and its callers. Instead pass the proper states in or dig them up from the top level atomic state.
Note that intel_plane_atomic_check_with_state() itself isn't allowed to use the top level atomic state as there is none when it gets called from the legacy cursor short circuit path.
Signed-off-by: Ville Syrjälä ville.syrjala@linux.intel.com
drivers/gpu/drm/i915/intel_atomic_plane.c | 40 +++++++++++++++++++------------ drivers/gpu/drm/i915/intel_display.c | 12 ++++++---- drivers/gpu/drm/i915/intel_drv.h | 16 +++++++++++-- 3 files changed, 46 insertions(+), 22 deletions(-)
diff --git a/drivers/gpu/drm/i915/intel_atomic_plane.c b/drivers/gpu/drm/i915/intel_atomic_plane.c index ee76fab7bb6f..7cdbe9ae2c96 100644 --- a/drivers/gpu/drm/i915/intel_atomic_plane.c +++ b/drivers/gpu/drm/i915/intel_atomic_plane.c @@ -107,7 +107,9 @@ intel_plane_destroy_state(struct drm_plane *plane, drm_atomic_helper_plane_destroy_state(plane, state); }
-int intel_plane_atomic_check_with_state(struct intel_crtc_state *crtc_state, +int intel_plane_atomic_check_with_state(const struct intel_crtc_state *old_crtc_state,
struct intel_crtc_state *crtc_state,
const struct intel_plane_state *old_plane_state, struct intel_plane_state *intel_state)
{ struct drm_plane *plane = intel_state->base.plane; @@ -124,7 +126,7 @@ int intel_plane_atomic_check_with_state(struct intel_crtc_state *crtc_state, * anything driver-specific we need to test in that case, so * just return success. */
- if (!intel_state->base.crtc && !plane->state->crtc)
if (!intel_state->base.crtc && !old_plane_state->base.crtc) return 0;
/* Clip all planes to CRTC size, or 0x0 if CRTC is disabled */
@@ -194,17 +196,21 @@ int intel_plane_atomic_check_with_state(struct intel_crtc_state *crtc_state, else crtc_state->active_planes &= ~BIT(intel_plane->id);
- return intel_plane_atomic_calc_changes(&crtc_state->base, state);
- return intel_plane_atomic_calc_changes(old_crtc_state,
&crtc_state->base,
old_plane_state,
state);
}
static int intel_plane_atomic_check(struct drm_plane *plane, struct drm_plane_state *state)
new_plane_state?
I was trying to keep these patches as minimal as possible. So I was avoiding renaming things that already had names. I do agree whole heartedly that we have to rename these things but I was thinking we could perhaps try to do that with coccinelle. Not quite sure if that's feasible but seems like an interesting thing to try out.
{
- struct drm_crtc *crtc = state->crtc;
- const struct drm_plane_state *old_plane_state =
drm_atomic_get_old_plane_state(state->state, plane);
- struct drm_crtc *crtc = state->crtc ?: old_plane_state->crtc;
- const struct drm_crtc_state *old_crtc_state; struct drm_crtc_state *drm_crtc_state;
- crtc = crtc ? crtc : plane->state->crtc;
- /*
- Both crtc and plane->crtc could be NULL if we're updating a
- property while the plane is disabled. We don't actually have
@@ -214,29 +220,33 @@ static int intel_plane_atomic_check(struct drm_plane *plane, if (!crtc) return 0;
- drm_crtc_state = drm_atomic_get_existing_crtc_state(state->state, crtc);
- if (WARN_ON(!drm_crtc_state))
return -EINVAL;
- old_crtc_state = drm_atomic_get_old_crtc_state(state->state, crtc);
- drm_crtc_state = drm_atomic_get_new_crtc_state(state->state, crtc);
new_crtc_state?
Yes. In this case that definitely makes sense since it's not used elsewhere.
- return intel_plane_atomic_check_with_state(to_intel_crtc_state(drm_crtc_state),
- return intel_plane_atomic_check_with_state(to_intel_crtc_state(old_crtc_state),
to_intel_crtc_state(drm_crtc_state),
to_intel_plane_state(old_plane_state), to_intel_plane_state(state));
}
static void intel_plane_atomic_update(struct drm_plane *plane, struct drm_plane_state *old_state) {
- struct intel_atomic_state *state = to_intel_atomic_state(old_state->state); struct intel_plane *intel_plane = to_intel_plane(plane);
- struct intel_plane_state *intel_state =
to_intel_plane_state(plane->state);
- struct drm_crtc *crtc = plane->state->crtc ?: old_state->crtc;
const struct intel_plane_state *intel_state =
intel_atomic_get_new_plane_state(state, intel_plane);
struct drm_crtc *crtc = intel_state->base.crtc ?: old_state->crtc;
if (intel_state->base.visible) {
const struct intel_crtc_state *intel_crtc_state =
intel_atomic_get_new_crtc_state(state, to_intel_crtc(crtc));
trace_intel_update_plane(plane, to_intel_crtc(crtc));
intel_plane->update_plane(intel_plane,
to_intel_crtc_state(crtc->state),
intel_state);
} else { trace_intel_disable_plane(plane, to_intel_crtc(crtc));intel_crtc_state, intel_state);
I think with so many names, might be better to use new_crtc_state and new_plane_state here.
I guess this function is small enough that doing the renames immediately does make sense.
State is used so much as keyword in atomic that with multiple states, intel_state becomes as descriptive as void *ptr. :)
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index cdfa95be4b8e..6440479d6fe2 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -11011,7 +11011,7 @@ static bool intel_wm_need_update(struct drm_plane *plane, return false; }
-static bool needs_scaling(struct intel_plane_state *state) +static bool needs_scaling(const struct intel_plane_state *state) { int src_w = drm_rect_width(&state->base.src) >> 16; int src_h = drm_rect_height(&state->base.src) >> 16; @@ -11021,7 +11021,9 @@ static bool needs_scaling(struct intel_plane_state *state) return (src_w != dst_w || src_h != dst_h); }
-int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state, +int intel_plane_atomic_calc_changes(const struct intel_crtc_state *old_crtc_state,
struct drm_crtc_state *crtc_state,
const struct intel_plane_state *old_plane_state, struct drm_plane_state *plane_state)
{ struct intel_crtc_state *pipe_config = to_intel_crtc_state(crtc_state); @@ -11030,10 +11032,8 @@ int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state, struct intel_plane *plane = to_intel_plane(plane_state->plane); struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = to_i915(dev);
- struct intel_plane_state *old_plane_state =
bool mode_changed = needs_modeset(crtc_state);to_intel_plane_state(plane->base.state);
- bool was_crtc_enabled = crtc->state->active;
- bool was_crtc_enabled = old_crtc_state->base.active; bool is_crtc_enabled = crtc_state->active; bool turn_off, turn_on, visible, was_visible; struct drm_framebuffer *fb = plane_state->fb;
@@ -13660,6 +13660,8 @@ intel_legacy_cursor_update(struct drm_plane *plane, new_plane_state->crtc_h = crtc_h;
ret = intel_plane_atomic_check_with_state(to_intel_crtc_state(crtc->state),
^old crtc state here?
to_intel_crtc_state(crtc->state), /* FIXME need a new crtc state? */
and crtc_state here? You already pass both to this function?
to_intel_plane_state(plane->state),
and old_plane_state here?
to_intel_plane_state(new_plane_state));
if (ret) goto out_free; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index e9d61a03c46e..ea36d1a61e86 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1207,6 +1207,14 @@ hdmi_to_dig_port(struct intel_hdmi *intel_hdmi) return container_of(intel_hdmi, struct intel_digital_port, hdmi); }
+static inline struct intel_plane_state * +intel_atomic_get_new_plane_state(struct intel_atomic_state *state,
struct intel_plane *plane)
+{
- return to_intel_plane_state(drm_atomic_get_new_plane_state(&state->base,
&plane->base));
+}
static inline struct intel_crtc_state * intel_atomic_get_old_crtc_state(struct intel_atomic_state *state, struct intel_crtc *crtc) @@ -1439,7 +1447,9 @@ int intel_plane_atomic_set_property(struct drm_plane *plane, struct drm_plane_state *state, struct drm_property *property, uint64_t val); -int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state, +int intel_plane_atomic_calc_changes(const struct intel_crtc_state *old_crtc_state,
struct drm_crtc_state *crtc_state,
const struct intel_plane_state *old_plane_state, struct drm_plane_state *plane_state);
void assert_pch_transcoder_disabled(struct drm_i915_private *dev_priv, @@ -1990,7 +2000,9 @@ struct drm_plane_state *intel_plane_duplicate_state(struct drm_plane *plane); void intel_plane_destroy_state(struct drm_plane *plane, struct drm_plane_state *state); extern const struct drm_plane_helper_funcs intel_plane_helper_funcs; -int intel_plane_atomic_check_with_state(struct intel_crtc_state *crtc_state, +int intel_plane_atomic_check_with_state(const struct intel_crtc_state *old_crtc_state,
struct intel_crtc_state *crtc_state,
const struct intel_plane_state *old_plane_state, struct intel_plane_state *intel_state);
/* intel_color.c */
Please for this whole patch, use old/new_plane/crtc_state, or it becomes unreadable very fast. :)
The code is already pretty much unreadable in places due to this. Hence I was aiming for doing a mass rename later.
From: Ville Syrjälä ville.syrjala@linux.intel.com
Eliminate plane->state and crtc->state usage from intel_plane_atomic_check_with_state() and its callers. Instead pass the proper states in or dig them up from the top level atomic state.
Note that intel_plane_atomic_check_with_state() itself isn't allowed to use the top level atomic state as there is none when it gets called from the legacy cursor short circuit path.
v2: Rename some variables for easier comprehension (Maarten)
Cc: Maarten Lankhorst maarten.lankhorst@linux.intel.com Signed-off-by: Ville Syrjälä ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/intel_atomic_plane.c | 49 +++++++++++++++++++------------ drivers/gpu/drm/i915/intel_display.c | 12 ++++---- drivers/gpu/drm/i915/intel_drv.h | 16 ++++++++-- 3 files changed, 51 insertions(+), 26 deletions(-)
diff --git a/drivers/gpu/drm/i915/intel_atomic_plane.c b/drivers/gpu/drm/i915/intel_atomic_plane.c index ee76fab7bb6f..8e6dc159f64d 100644 --- a/drivers/gpu/drm/i915/intel_atomic_plane.c +++ b/drivers/gpu/drm/i915/intel_atomic_plane.c @@ -107,7 +107,9 @@ intel_plane_destroy_state(struct drm_plane *plane, drm_atomic_helper_plane_destroy_state(plane, state); }
-int intel_plane_atomic_check_with_state(struct intel_crtc_state *crtc_state, +int intel_plane_atomic_check_with_state(const struct intel_crtc_state *old_crtc_state, + struct intel_crtc_state *crtc_state, + const struct intel_plane_state *old_plane_state, struct intel_plane_state *intel_state) { struct drm_plane *plane = intel_state->base.plane; @@ -124,7 +126,7 @@ int intel_plane_atomic_check_with_state(struct intel_crtc_state *crtc_state, * anything driver-specific we need to test in that case, so * just return success. */ - if (!intel_state->base.crtc && !plane->state->crtc) + if (!intel_state->base.crtc && !old_plane_state->base.crtc) return 0;
/* Clip all planes to CRTC size, or 0x0 if CRTC is disabled */ @@ -194,16 +196,21 @@ int intel_plane_atomic_check_with_state(struct intel_crtc_state *crtc_state, else crtc_state->active_planes &= ~BIT(intel_plane->id);
- return intel_plane_atomic_calc_changes(&crtc_state->base, state); + return intel_plane_atomic_calc_changes(old_crtc_state, + &crtc_state->base, + old_plane_state, + state); }
static int intel_plane_atomic_check(struct drm_plane *plane, - struct drm_plane_state *state) + struct drm_plane_state *new_plane_state) { - struct drm_crtc *crtc = state->crtc; - struct drm_crtc_state *drm_crtc_state; - - crtc = crtc ? crtc : plane->state->crtc; + struct drm_atomic_state *state = new_plane_state->state; + const struct drm_plane_state *old_plane_state = + drm_atomic_get_old_plane_state(state, plane); + struct drm_crtc *crtc = new_plane_state->crtc ?: old_plane_state->crtc; + const struct drm_crtc_state *old_crtc_state; + struct drm_crtc_state *new_crtc_state;
/* * Both crtc and plane->crtc could be NULL if we're updating a @@ -214,29 +221,33 @@ static int intel_plane_atomic_check(struct drm_plane *plane, if (!crtc) return 0;
- drm_crtc_state = drm_atomic_get_existing_crtc_state(state->state, crtc); - if (WARN_ON(!drm_crtc_state)) - return -EINVAL; + old_crtc_state = drm_atomic_get_old_crtc_state(state, crtc); + new_crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
- return intel_plane_atomic_check_with_state(to_intel_crtc_state(drm_crtc_state), - to_intel_plane_state(state)); + return intel_plane_atomic_check_with_state(to_intel_crtc_state(old_crtc_state), + to_intel_crtc_state(new_crtc_state), + to_intel_plane_state(old_plane_state), + to_intel_plane_state(new_plane_state)); }
static void intel_plane_atomic_update(struct drm_plane *plane, struct drm_plane_state *old_state) { + struct intel_atomic_state *state = to_intel_atomic_state(old_state->state); struct intel_plane *intel_plane = to_intel_plane(plane); - struct intel_plane_state *intel_state = - to_intel_plane_state(plane->state); - struct drm_crtc *crtc = plane->state->crtc ?: old_state->crtc; + const struct intel_plane_state *new_plane_state = + intel_atomic_get_new_plane_state(state, intel_plane); + struct drm_crtc *crtc = new_plane_state->base.crtc ?: old_state->crtc; + + if (new_plane_state->base.visible) { + const struct intel_crtc_state *new_crtc_state = + intel_atomic_get_new_crtc_state(state, to_intel_crtc(crtc));
- if (intel_state->base.visible) { trace_intel_update_plane(plane, to_intel_crtc(crtc));
intel_plane->update_plane(intel_plane, - to_intel_crtc_state(crtc->state), - intel_state); + new_crtc_state, new_plane_state); } else { trace_intel_disable_plane(plane, to_intel_crtc(crtc)); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index cdfa95be4b8e..6440479d6fe2 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -11011,7 +11011,7 @@ static bool intel_wm_need_update(struct drm_plane *plane, return false; }
-static bool needs_scaling(struct intel_plane_state *state) +static bool needs_scaling(const struct intel_plane_state *state) { int src_w = drm_rect_width(&state->base.src) >> 16; int src_h = drm_rect_height(&state->base.src) >> 16; @@ -11021,7 +11021,9 @@ static bool needs_scaling(struct intel_plane_state *state) return (src_w != dst_w || src_h != dst_h); }
-int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state, +int intel_plane_atomic_calc_changes(const struct intel_crtc_state *old_crtc_state, + struct drm_crtc_state *crtc_state, + const struct intel_plane_state *old_plane_state, struct drm_plane_state *plane_state) { struct intel_crtc_state *pipe_config = to_intel_crtc_state(crtc_state); @@ -11030,10 +11032,8 @@ int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state, struct intel_plane *plane = to_intel_plane(plane_state->plane); struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = to_i915(dev); - struct intel_plane_state *old_plane_state = - to_intel_plane_state(plane->base.state); bool mode_changed = needs_modeset(crtc_state); - bool was_crtc_enabled = crtc->state->active; + bool was_crtc_enabled = old_crtc_state->base.active; bool is_crtc_enabled = crtc_state->active; bool turn_off, turn_on, visible, was_visible; struct drm_framebuffer *fb = plane_state->fb; @@ -13660,6 +13660,8 @@ intel_legacy_cursor_update(struct drm_plane *plane, new_plane_state->crtc_h = crtc_h;
ret = intel_plane_atomic_check_with_state(to_intel_crtc_state(crtc->state), + to_intel_crtc_state(crtc->state), /* FIXME need a new crtc state? */ + to_intel_plane_state(plane->state), to_intel_plane_state(new_plane_state)); if (ret) goto out_free; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index e9d61a03c46e..ea36d1a61e86 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1207,6 +1207,14 @@ hdmi_to_dig_port(struct intel_hdmi *intel_hdmi) return container_of(intel_hdmi, struct intel_digital_port, hdmi); }
+static inline struct intel_plane_state * +intel_atomic_get_new_plane_state(struct intel_atomic_state *state, + struct intel_plane *plane) +{ + return to_intel_plane_state(drm_atomic_get_new_plane_state(&state->base, + &plane->base)); +} + static inline struct intel_crtc_state * intel_atomic_get_old_crtc_state(struct intel_atomic_state *state, struct intel_crtc *crtc) @@ -1439,7 +1447,9 @@ int intel_plane_atomic_set_property(struct drm_plane *plane, struct drm_plane_state *state, struct drm_property *property, uint64_t val); -int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state, +int intel_plane_atomic_calc_changes(const struct intel_crtc_state *old_crtc_state, + struct drm_crtc_state *crtc_state, + const struct intel_plane_state *old_plane_state, struct drm_plane_state *plane_state);
void assert_pch_transcoder_disabled(struct drm_i915_private *dev_priv, @@ -1990,7 +2000,9 @@ struct drm_plane_state *intel_plane_duplicate_state(struct drm_plane *plane); void intel_plane_destroy_state(struct drm_plane *plane, struct drm_plane_state *state); extern const struct drm_plane_helper_funcs intel_plane_helper_funcs; -int intel_plane_atomic_check_with_state(struct intel_crtc_state *crtc_state, +int intel_plane_atomic_check_with_state(const struct intel_crtc_state *old_crtc_state, + struct intel_crtc_state *crtc_state, + const struct intel_plane_state *old_plane_state, struct intel_plane_state *intel_state);
/* intel_color.c */
From: Ville Syrjälä ville.syrjala@linux.intel.com
Dig up the appropriate new crtc and plane states from the top level atomic state in intel_pre_plane_update() and intel_post_plane_update().
Signed-off-by: Ville Syrjälä ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/intel_display.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 6440479d6fe2..182881c4d6d3 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4994,7 +4994,8 @@ static void intel_post_plane_update(struct intel_crtc_state *old_crtc_state) struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->base.crtc); struct drm_atomic_state *old_state = old_crtc_state->base.state; struct intel_crtc_state *pipe_config = - to_intel_crtc_state(crtc->base.state); + intel_atomic_get_new_crtc_state(to_intel_atomic_state(old_state), + crtc); struct drm_plane *primary = crtc->base.primary; struct drm_plane_state *old_pri_state = drm_atomic_get_existing_plane_state(old_state, primary); @@ -5006,7 +5007,8 @@ static void intel_post_plane_update(struct intel_crtc_state *old_crtc_state)
if (old_pri_state) { struct intel_plane_state *primary_state = - to_intel_plane_state(primary->state); + intel_atomic_get_new_plane_state(to_intel_atomic_state(old_state), + to_intel_plane(primary)); struct intel_plane_state *old_primary_state = to_intel_plane_state(old_pri_state);
@@ -5035,7 +5037,8 @@ static void intel_pre_plane_update(struct intel_crtc_state *old_crtc_state,
if (old_pri_state) { struct intel_plane_state *primary_state = - to_intel_plane_state(primary->state); + intel_atomic_get_new_plane_state(old_intel_state, + to_intel_plane(primary)); struct intel_plane_state *old_primary_state = to_intel_plane_state(old_pri_state);
From: Ville Syrjälä ville.syrjala@linux.intel.com
Pass the correct new crtc state to intel_update_pipe_config() instead of using crtc->state.
Signed-off-by: Ville Syrjälä ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/intel_display.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-)
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 182881c4d6d3..0c18e3e7c6a5 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3633,15 +3633,14 @@ static bool intel_crtc_has_pending_flip(struct drm_crtc *crtc) return pending; }
-static void intel_update_pipe_config(struct intel_crtc *crtc, - struct intel_crtc_state *old_crtc_state) +static void intel_update_pipe_config(const struct intel_crtc_state *old_crtc_state, + const struct intel_crtc_state *new_crtc_state) { + struct intel_crtc *crtc = to_intel_crtc(new_crtc_state->base.crtc); struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); - struct intel_crtc_state *pipe_config = - to_intel_crtc_state(crtc->base.state);
/* drm_atomic_helper_update_legacy_modeset_state might not be called. */ - crtc->base.mode = crtc->base.state->mode; + crtc->base.mode = new_crtc_state->base.mode;
/* * Update pipe size and adjust fitter if needed: the reason for this is @@ -3653,17 +3652,17 @@ static void intel_update_pipe_config(struct intel_crtc *crtc, */
I915_WRITE(PIPESRC(crtc->pipe), - ((pipe_config->pipe_src_w - 1) << 16) | - (pipe_config->pipe_src_h - 1)); + ((new_crtc_state->pipe_src_w - 1) << 16) | + (new_crtc_state->pipe_src_h - 1));
/* on skylake this is done by detaching scalers */ if (INTEL_GEN(dev_priv) >= 9) { skl_detach_scalers(crtc);
- if (pipe_config->pch_pfit.enabled) + if (new_crtc_state->pch_pfit.enabled) skylake_pfit_enable(crtc); } else if (HAS_PCH_SPLIT(dev_priv)) { - if (pipe_config->pch_pfit.enabled) + if (new_crtc_state->pch_pfit.enabled) ironlake_pfit_enable(crtc); else if (old_crtc_state->pch_pfit.enabled) ironlake_pfit_disable(crtc, true); @@ -13560,7 +13559,7 @@ static void intel_begin_crtc_commit(struct drm_crtc *crtc, goto out;
if (intel_cstate->update_pipe) - intel_update_pipe_config(intel_crtc, old_intel_cstate); + intel_update_pipe_config(old_intel_cstate, intel_cstate); else if (INTEL_GEN(dev_priv) >= 9) skl_detach_scalers(intel_crtc);
From: Ville Syrjälä ville.syrjala@linux.intel.com
We already have the correct new crtc state so just use that instead of crtc->state.
Signed-off-by: Ville Syrjälä ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/intel_display.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 0c18e3e7c6a5..791204c8621c 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -12970,7 +12970,7 @@ static void skl_update_crtcs(struct drm_atomic_state *state, unsigned int cmask = drm_crtc_mask(crtc);
intel_crtc = to_intel_crtc(crtc); - cstate = to_intel_crtc_state(crtc->state); + cstate = to_intel_crtc_state(new_crtc_state); pipe = intel_crtc->pipe;
if (updated & cmask || !cstate->base.active) @@ -13073,7 +13073,7 @@ static void intel_atomic_commit_tail(struct drm_atomic_state *state) intel_check_cpu_fifo_underruns(dev_priv); intel_check_pch_fifo_underruns(dev_priv);
- if (!crtc->state->active) { + if (!new_crtc_state->active) { /* * Make sure we don't call initial_watermarks * for ILK-style watermark updates. @@ -13082,7 +13082,7 @@ static void intel_atomic_commit_tail(struct drm_atomic_state *state) */ if (INTEL_GEN(dev_priv) >= 9) dev_priv->display.initial_watermarks(intel_state, - to_intel_crtc_state(crtc->state)); + to_intel_crtc_state(new_crtc_state)); } } }
Op 06-07-17 om 22:24 schreef ville.syrjala@linux.intel.com:
From: Ville Syrjälä ville.syrjala@linux.intel.com
We already have the correct new crtc state so just use that instead of crtc->state.
For patches 1-3 and 5-7:
Reviewed-by: Maarten Lankhorst maarten.lankhorst@linux.intel.com
From: Ville Syrjälä ville.syrjala@linux.intel.com
Add a small helper that gives us dynamically growing arrays. We have a couple hand rolled implementations of this in the atomic code, which we can unify to use a common implementation.
Signed-off-by: Ville Syrjälä ville.syrjala@linux.intel.com --- Documentation/gpu/drm-utils.rst | 15 +++++++ Documentation/gpu/index.rst | 1 + drivers/gpu/drm/Makefile | 2 +- drivers/gpu/drm/drm_dynarray.c | 97 +++++++++++++++++++++++++++++++++++++++++ include/drm/drm_dynarray.h | 54 +++++++++++++++++++++++ 5 files changed, 168 insertions(+), 1 deletion(-) create mode 100644 Documentation/gpu/drm-utils.rst create mode 100644 drivers/gpu/drm/drm_dynarray.c create mode 100644 include/drm/drm_dynarray.h
diff --git a/Documentation/gpu/drm-utils.rst b/Documentation/gpu/drm-utils.rst new file mode 100644 index 000000000000..bff8c899d7cd --- /dev/null +++ b/Documentation/gpu/drm-utils.rst @@ -0,0 +1,15 @@ +============= +DRM Utilities +============= + +Dynamic arrays +-------------- + +.. kernel-doc:: drivers/gpu/drm/drm_dynarray.c + :doc: Dynamic arrays + +.. kernel-doc:: drivers/gpu/drm/drm_dynarray.c + :export: + +.. kernel-doc:: include/drm/drm_dynarray.h + :internal: diff --git a/Documentation/gpu/index.rst b/Documentation/gpu/index.rst index 35d673bf9b56..b7d196e5c70d 100644 --- a/Documentation/gpu/index.rst +++ b/Documentation/gpu/index.rst @@ -10,6 +10,7 @@ Linux GPU Driver Developer's Guide drm-kms drm-kms-helpers drm-uapi + drm-utils i915 meson pl111 diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index 24a066e1841c..b637a34df388 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -3,7 +3,7 @@ # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
drm-y := drm_auth.o drm_bufs.o drm_cache.o \ - drm_context.o drm_dma.o \ + drm_context.o drm_dma.o drm_dynarray.o \ drm_file.o drm_gem.o drm_ioctl.o drm_irq.o \ drm_lock.o drm_memory.o drm_drv.o \ drm_scatter.o drm_pci.o \ diff --git a/drivers/gpu/drm/drm_dynarray.c b/drivers/gpu/drm/drm_dynarray.c new file mode 100644 index 000000000000..69a8819ecb62 --- /dev/null +++ b/drivers/gpu/drm/drm_dynarray.c @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2017 Intel Corp. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include <linux/slab.h> +#include <linux/string.h> +#include <drm/drm_dynarray.h> + +/** + * DOC: Dynamic arrays + * + * Helper that provides dynamically growing arrays. The array + * must be initilaized to specify the size of each element, and + * space can be reserved in the array by specifying the element + * index to be used. + */ + +/** + * drm_dynarray_init - Initialize the dynamic array + * @dynarr: the dynamic array + * @elem_size: size of each element in bytes + * + * Initialize the dynamic array and specify the size of + * each element of the array. + */ +void drm_dynarray_init(struct drm_dynarray *dynarr, + unsigned int elem_size) +{ + memset(dynarr, 0, sizeof(*dynarr)); + dynarr->elem_size = elem_size; +} +EXPORT_SYMBOL(drm_dynarray_init); + +/** + * drm_dynarray_fini - Finalize the dynamic array + * @dynarr: the dynamic array + * + * Finalize the dynamic array, ie. free the memory + * used by the array. + */ +void drm_dynarray_fini(struct drm_dynarray *dynarr) +{ + kfree(dynarr->elems); + memset(dynarr, 0, sizeof(*dynarr)); +} +EXPORT_SYMBOL(drm_dynarray_fini); + +/** + * drm_dynarray_reserve - Reserve space in the dynamic array + * @dynarr: the dynamic array + * @index: the index of the element to reserve + * + * Grow the array sufficiently to make sure @index points + * to a valid memory location within the array. + */ +int drm_dynarray_reserve(struct drm_dynarray *dynarr, + unsigned int index) +{ + unsigned int num_elems = index + 1; + unsigned int old_num_elems = dynarr->num_elems; + void *elems; + + if (num_elems <= old_num_elems) + return 0; + + elems = krealloc(dynarr->elems, + num_elems * dynarr->elem_size, GFP_KERNEL); + if (!elems) + return -ENOMEM; + + dynarr->elems = elems; + dynarr->num_elems = num_elems; + + memset(drm_dynarray_elem(dynarr, old_num_elems), 0, + (num_elems - old_num_elems) * dynarr->elem_size); + + return 0; +} +EXPORT_SYMBOL(drm_dynarray_reserve); diff --git a/include/drm/drm_dynarray.h b/include/drm/drm_dynarray.h new file mode 100644 index 000000000000..c8cd088a3a3b --- /dev/null +++ b/include/drm/drm_dynarray.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2017 Intel Corp. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef DRM_DYNARRAY_H +#define DRM_DYNARRAY_H + +struct drm_dynarray { + void *elems; + unsigned int elem_size, num_elems; +}; + +/** + * drm_dynarray_elem - Return a pointer to an element + * @dynarr: the dynamic array + * @index: the index of the element + * + * Returns: + * A pointer to the element at @index in the array. + */ +static inline void *drm_dynarray_elem(const struct drm_dynarray *dynarr, + unsigned int index) +{ + if (index >= dynarr->num_elems) + return NULL; + return dynarr->elems + index * dynarr->elem_size; +} + +int drm_dynarray_reserve(struct drm_dynarray *dynarr, + unsigned int index); + +void drm_dynarray_init(struct drm_dynarray *dynarr, + unsigned int elem_size); +void drm_dynarray_fini(struct drm_dynarray *dynarr); + +#endif
From: Ville Syrjälä ville.syrjala@linux.intel.com
state->connectors[] can grows dynamically, so we can switch over to using the new drm_dynarray.
Signed-off-by: Ville Syrjälä ville.syrjala@linux.intel.com --- drivers/gpu/drm/drm_atomic.c | 49 +++++++++++++++++++------------------ drivers/gpu/drm/drm_atomic_helper.c | 4 +-- include/drm/drm_atomic.h | 42 ++++++++++++++++++------------- 3 files changed, 52 insertions(+), 43 deletions(-)
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 09ca662fcd35..1663ec3626a1 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -28,6 +28,7 @@
#include <drm/drmP.h> #include <drm/drm_atomic.h> +#include <drm/drm_dynarray.h> #include <drm/drm_mode.h> #include <drm/drm_print.h> #include <linux/sync_file.h> @@ -53,7 +54,7 @@ EXPORT_SYMBOL(__drm_crtc_commit_free); */ void drm_atomic_state_default_release(struct drm_atomic_state *state) { - kfree(state->connectors); + drm_dynarray_fini(&state->connectors); kfree(state->crtcs); kfree(state->planes); kfree(state->private_objs); @@ -87,6 +88,9 @@ drm_atomic_state_init(struct drm_device *dev, struct drm_atomic_state *state) if (!state->planes) goto fail;
+ drm_dynarray_init(&state->connectors, + sizeof(struct __drm_connectors_state)); + state->dev = dev;
DRM_DEBUG_ATOMIC("Allocated atomic state %p\n", state); @@ -142,15 +146,17 @@ void drm_atomic_state_default_clear(struct drm_atomic_state *state) DRM_DEBUG_ATOMIC("Clearing atomic state %p\n", state);
for (i = 0; i < state->num_connector; i++) { - struct drm_connector *connector = state->connectors[i].ptr; + struct __drm_connectors_state *c = + __drm_atomic_state_connector(state, i); + struct drm_connector *connector = c->ptr;
if (!connector) continue;
connector->funcs->atomic_destroy_state(connector, - state->connectors[i].state); - state->connectors[i].ptr = NULL; - state->connectors[i].state = NULL; + c->state); + c->ptr = NULL; + c->state = NULL; drm_connector_put(connector); }
@@ -1064,6 +1070,7 @@ drm_atomic_get_connector_state(struct drm_atomic_state *state, int ret, index; struct drm_mode_config *config = &connector->dev->mode_config; struct drm_connector_state *connector_state; + struct __drm_connectors_state *c;
WARN_ON(!state->acquire_ctx);
@@ -1073,35 +1080,29 @@ drm_atomic_get_connector_state(struct drm_atomic_state *state,
index = drm_connector_index(connector);
- if (index >= state->num_connector) { - struct __drm_connnectors_state *c; - int alloc = max(index + 1, config->num_connector); - - c = krealloc(state->connectors, alloc * sizeof(*state->connectors), GFP_KERNEL); - if (!c) - return ERR_PTR(-ENOMEM); - - state->connectors = c; - memset(&state->connectors[state->num_connector], 0, - sizeof(*state->connectors) * (alloc - state->num_connector)); + ret = drm_dynarray_reserve(&state->connectors, + max(index, config->num_connector - 1)); + if (ret) + return ERR_PTR(ret);
- state->num_connector = alloc; - } + c = __drm_atomic_state_connector(state, index);
- if (state->connectors[index].state) - return state->connectors[index].state; + if (c->state) + return c->state;
connector_state = connector->funcs->atomic_duplicate_state(connector); if (!connector_state) return ERR_PTR(-ENOMEM);
drm_connector_get(connector); - state->connectors[index].state = connector_state; - state->connectors[index].old_state = connector->state; - state->connectors[index].new_state = connector_state; - state->connectors[index].ptr = connector; + c->state = connector_state; + c->old_state = connector->state; + c->new_state = connector_state; + c->ptr = connector; connector_state->state = state;
+ state->num_connector = state->connectors.num_elems; + DRM_DEBUG_ATOMIC("Added [CONNECTOR:%d:%s] %p state to %p\n", connector->base.id, connector->name, connector_state, state); diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 667ec97d4efb..2d747ac35ecf 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -2297,7 +2297,7 @@ void drm_atomic_helper_swap_state(struct drm_atomic_state *state, old_conn_state->state = state; new_conn_state->state = NULL;
- state->connectors[i].state = old_conn_state; + __drm_atomic_state_connector(state, i)->state = old_conn_state; connector->state = new_conn_state; }
@@ -2871,7 +2871,7 @@ int drm_atomic_helper_commit_duplicated_state(struct drm_atomic_state *state, state->crtcs[i].old_state = crtc->state;
for_each_new_connector_in_state(state, connector, new_conn_state, i) - state->connectors[i].old_state = connector->state; + __drm_atomic_state_connector(state, i)->old_state = connector->state;
return drm_atomic_commit(state); } diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h index dcc8e0cdb7ff..44316ce45fbb 100644 --- a/include/drm/drm_atomic.h +++ b/include/drm/drm_atomic.h @@ -29,6 +29,7 @@ #define DRM_ATOMIC_H_
#include <drm/drm_crtc.h> +#include <drm/drm_dynarray.h>
/** * struct drm_crtc_commit - track modeset commits on a CRTC @@ -149,7 +150,7 @@ struct __drm_crtcs_state { unsigned last_vblank_count; };
-struct __drm_connnectors_state { +struct __drm_connectors_state { struct drm_connector *ptr; struct drm_connector_state *state, *old_state, *new_state; }; @@ -226,7 +227,7 @@ struct drm_atomic_state { struct __drm_planes_state *planes; struct __drm_crtcs_state *crtcs; int num_connector; - struct __drm_connnectors_state *connectors; + struct drm_dynarray connectors; /* struct __drm_connectors_state [] */; int num_private_objs; struct __drm_private_objs_state *private_objs;
@@ -241,6 +242,13 @@ struct drm_atomic_state { struct work_struct commit_work; };
+static inline struct __drm_connectors_state * +__drm_atomic_state_connector(const struct drm_atomic_state *state, + unsigned int index) +{ + return drm_dynarray_elem(&state->connectors, index); +} + void __drm_crtc_commit_free(struct kref *kref);
/** @@ -441,7 +449,7 @@ drm_atomic_get_existing_connector_state(struct drm_atomic_state *state, if (index >= state->num_connector) return NULL;
- return state->connectors[index].state; + return __drm_atomic_state_connector(state, index)->state; }
/** @@ -461,7 +469,7 @@ drm_atomic_get_old_connector_state(struct drm_atomic_state *state, if (index >= state->num_connector) return NULL;
- return state->connectors[index].old_state; + return __drm_atomic_state_connector(state, index)->old_state; }
/** @@ -481,7 +489,7 @@ drm_atomic_get_new_connector_state(struct drm_atomic_state *state, if (index >= state->num_connector) return NULL;
- return state->connectors[index].new_state; + return __drm_atomic_state_connector(state, index)->new_state; }
/** @@ -573,9 +581,9 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p); */ #define for_each_connector_in_state(__state, connector, connector_state, __i) \ for ((__i) = 0; \ - (__i) < (__state)->num_connector && \ - ((connector) = (__state)->connectors[__i].ptr, \ - (connector_state) = (__state)->connectors[__i].state, 1); \ + (__i) < (__state)->num_connector && \ + ((connector) = __drm_atomic_state_connector(__state, __i)->ptr, \ + (connector_state) = __drm_atomic_state_connector(__state, __i)->state, 1); \ (__i)++) \ for_each_if (connector)
@@ -595,10 +603,10 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p); */ #define for_each_oldnew_connector_in_state(__state, connector, old_connector_state, new_connector_state, __i) \ for ((__i) = 0; \ - (__i) < (__state)->num_connector && \ - ((connector) = (__state)->connectors[__i].ptr, \ - (old_connector_state) = (__state)->connectors[__i].old_state, \ - (new_connector_state) = (__state)->connectors[__i].new_state, 1); \ + (__i) < (__state)->num_connector && \ + ((connector) = __drm_atomic_state_connector(__state, __i)->ptr, \ + (old_connector_state) = __drm_atomic_state_connector(__state, __i)->old_state, \ + (new_connector_state) = __drm_atomic_state_connector(__state, __i)->new_state, 1); \ (__i)++) \ for_each_if (connector)
@@ -616,9 +624,9 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p); */ #define for_each_old_connector_in_state(__state, connector, old_connector_state, __i) \ for ((__i) = 0; \ - (__i) < (__state)->num_connector && \ - ((connector) = (__state)->connectors[__i].ptr, \ - (old_connector_state) = (__state)->connectors[__i].old_state, 1); \ + (__i) < (__state)->num_connector && \ + ((connector) = __drm_atomic_state_connector(__state, __i)->ptr, \ + (old_connector_state) = __drm_atomic_state_connector(__state, __i)->old_state, 1); \ (__i)++) \ for_each_if (connector)
@@ -637,8 +645,8 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p); #define for_each_new_connector_in_state(__state, connector, new_connector_state, __i) \ for ((__i) = 0; \ (__i) < (__state)->num_connector && \ - ((connector) = (__state)->connectors[__i].ptr, \ - (new_connector_state) = (__state)->connectors[__i].new_state, 1); \ + ((connector) = __drm_atomic_state_connector(__state, __i)->ptr, \ + (new_connector_state) = __drm_atomic_state_connector(__state, __i)->new_state, 1); \ (__i)++) \ for_each_if (connector)
From: Ville Syrjälä ville.syrjala@linux.intel.com
We will never add private objects with a NULL state into the atomic state, hence checking for that is pointless.
Cc: Dhinakaran Pandiyan dhinakaran.pandiyan@intel.com Reviewed-by: Daniel Vetter daniel.vetter@ffwll.ch Signed-off-by: Ville Syrjälä ville.syrjala@linux.intel.com --- drivers/gpu/drm/drm_atomic.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 1663ec3626a1..a61e396b11a8 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -1019,8 +1019,7 @@ drm_atomic_get_private_obj_state(struct drm_atomic_state *state, void *obj, struct __drm_private_objs_state *arr;
for (i = 0; i < state->num_private_objs; i++) - if (obj == state->private_objs[i].obj && - state->private_objs[i].obj_state) + if (obj == state->private_objs[i].obj) return state->private_objs[i].obj_state;
num_objs = state->num_private_objs + 1;
From: Ville Syrjälä ville.syrjala@linux.intel.com
state->private_objs grows dynamically, so switch it over to use the new drm_dynarray helper.
Cc: Dhinakaran Pandiyan dhinakaran.pandiyan@intel.com Signed-off-by: Ville Syrjälä ville.syrjala@linux.intel.com --- drivers/gpu/drm/drm_atomic.c | 64 ++++++++++++++++++++----------------- drivers/gpu/drm/drm_atomic_helper.c | 2 +- include/drm/drm_atomic.h | 15 ++++++--- 3 files changed, 46 insertions(+), 35 deletions(-)
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index a61e396b11a8..5eb14c73c0fb 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -57,7 +57,7 @@ void drm_atomic_state_default_release(struct drm_atomic_state *state) drm_dynarray_fini(&state->connectors); kfree(state->crtcs); kfree(state->planes); - kfree(state->private_objs); + drm_dynarray_fini(&state->private_objs); } EXPORT_SYMBOL(drm_atomic_state_default_release);
@@ -90,6 +90,8 @@ drm_atomic_state_init(struct drm_device *dev, struct drm_atomic_state *state)
drm_dynarray_init(&state->connectors, sizeof(struct __drm_connectors_state)); + drm_dynarray_init(&state->private_objs, + sizeof(struct __drm_private_objs_state));
state->dev = dev;
@@ -193,12 +195,14 @@ void drm_atomic_state_default_clear(struct drm_atomic_state *state) }
for (i = 0; i < state->num_private_objs; i++) { - void *obj_state = state->private_objs[i].obj_state; - - state->private_objs[i].funcs->destroy_state(obj_state); - state->private_objs[i].obj = NULL; - state->private_objs[i].obj_state = NULL; - state->private_objs[i].funcs = NULL; + struct __drm_private_objs_state *p = + __drm_atomic_state_private_obj(state, i); + void *obj_state = p->obj_state; + + p->funcs->destroy_state(obj_state); + p->obj = NULL; + p->obj_state = NULL; + p->funcs = NULL; } state->num_private_objs = 0;
@@ -1014,36 +1018,36 @@ void * drm_atomic_get_private_obj_state(struct drm_atomic_state *state, void *obj, const struct drm_private_state_funcs *funcs) { - int index, num_objs, i; - size_t size; - struct __drm_private_objs_state *arr; - - for (i = 0; i < state->num_private_objs; i++) - if (obj == state->private_objs[i].obj) - return state->private_objs[i].obj_state; - - num_objs = state->num_private_objs + 1; - size = sizeof(*state->private_objs) * num_objs; - arr = krealloc(state->private_objs, size, GFP_KERNEL); - if (!arr) - return ERR_PTR(-ENOMEM); + struct __drm_private_objs_state *p; + int index = state->num_private_objs; + int ret, i; + + for (i = 0; i < state->num_private_objs; i++) { + p = __drm_atomic_state_private_obj(state, i); + + if (obj == p->obj) + return p->obj_state; + }
- state->private_objs = arr; - index = state->num_private_objs; - memset(&state->private_objs[index], 0, sizeof(*state->private_objs)); + ret = drm_dynarray_reserve(&state->private_objs, index); + if (ret) + return ERR_PTR(ret);
- state->private_objs[index].obj_state = funcs->duplicate_state(state, obj); - if (!state->private_objs[index].obj_state) + p = __drm_atomic_state_private_obj(state, index); + + p->obj_state = funcs->duplicate_state(state, obj); + if (!p->obj_state) return ERR_PTR(-ENOMEM);
- state->private_objs[index].obj = obj; - state->private_objs[index].funcs = funcs; - state->num_private_objs = num_objs; + p->obj = obj; + p->funcs = funcs; + + state->num_private_objs = index + 1;
DRM_DEBUG_ATOMIC("Added new private object state %p to %p\n", - state->private_objs[index].obj_state, state); + p->obj_state, state);
- return state->private_objs[index].obj_state; + return p->obj_state; } EXPORT_SYMBOL(drm_atomic_get_private_obj_state);
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 2d747ac35ecf..77b57cdf0460 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -2331,7 +2331,7 @@ void drm_atomic_helper_swap_state(struct drm_atomic_state *state, }
__for_each_private_obj(state, obj, obj_state, i, funcs) - funcs->swap_state(obj, &state->private_objs[i].obj_state); + funcs->swap_state(obj, &__drm_atomic_state_private_obj(state, i)->obj_state); } EXPORT_SYMBOL(drm_atomic_helper_swap_state);
diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h index 44316ce45fbb..809e8b4c3719 100644 --- a/include/drm/drm_atomic.h +++ b/include/drm/drm_atomic.h @@ -229,7 +229,7 @@ struct drm_atomic_state { int num_connector; struct drm_dynarray connectors; /* struct __drm_connectors_state [] */; int num_private_objs; - struct __drm_private_objs_state *private_objs; + struct drm_dynarray private_objs; /* struct __drm_private_objs_state [] */;
struct drm_modeset_acquire_ctx *acquire_ctx;
@@ -249,6 +249,13 @@ __drm_atomic_state_connector(const struct drm_atomic_state *state, return drm_dynarray_elem(&state->connectors, index); }
+static inline struct __drm_private_objs_state * +__drm_atomic_state_private_obj(const struct drm_atomic_state *state, + unsigned int index) +{ + return drm_dynarray_elem(&state->private_objs, index); +} + void __drm_crtc_commit_free(struct kref *kref);
/** @@ -832,9 +839,9 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p); #define __for_each_private_obj(__state, obj, obj_state, __i, __funcs) \ for ((__i) = 0; \ (__i) < (__state)->num_private_objs && \ - ((obj) = (__state)->private_objs[__i].obj, \ - (__funcs) = (__state)->private_objs[__i].funcs, \ - (obj_state) = (__state)->private_objs[__i].obj_state, \ + ((obj) = __drm_atomic_state_private_obj(__state, __i)->obj, \ + (__funcs) = __drm_atomic_state_private_obj(__state, __i)->funcs, \ + (obj_state) = __drm_atomic_state_private_obj(__state, __i)->obj_state, \ 1); \ (__i)++) \
From: Ville Syrjälä ville.syrjala@linux.intel.com
Make the atomic private object stuff less special by introducing proper base classes for the object and its state. Drivers can embed these in their own appropriate objects, after which these things will work exactly like the plane/crtc/connector states during atomic operations.
Cc: Dhinakaran Pandiyan dhinakaran.pandiyan@intel.com Reviewed-by: Daniel Vetter daniel.vetter@ffwll.ch Signed-off-by: Ville Syrjälä ville.syrjala@linux.intel.com --- drivers/gpu/drm/drm_atomic.c | 78 +++++++++++++++------ drivers/gpu/drm/drm_atomic_helper.c | 30 +++++++-- drivers/gpu/drm/drm_dp_mst_topology.c | 63 +++++++++-------- include/drm/drm_atomic.h | 123 +++++++++++++++++++++------------- include/drm/drm_atomic_helper.h | 4 ++ include/drm/drm_dp_mst_helper.h | 10 +++ 6 files changed, 206 insertions(+), 102 deletions(-)
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 5eb14c73c0fb..da7752230e4c 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -197,12 +197,14 @@ void drm_atomic_state_default_clear(struct drm_atomic_state *state) for (i = 0; i < state->num_private_objs; i++) { struct __drm_private_objs_state *p = __drm_atomic_state_private_obj(state, i); - void *obj_state = p->obj_state; + struct drm_private_obj *obj = p->ptr;
- p->funcs->destroy_state(obj_state); - p->obj = NULL; - p->obj_state = NULL; - p->funcs = NULL; + if (WARN_ON(!obj)) + continue; + + obj->funcs->atomic_destroy_state(obj, p->state); + p->ptr = NULL; + p->state = NULL; } state->num_private_objs = 0;
@@ -1000,11 +1002,44 @@ static void drm_atomic_plane_print_state(struct drm_printer *p, }
/** + * drm_atomic_private_obj_init - initialize private object + * @obj: private object + * @state: initial private object state + * @funcs: pointer to the struct of function pointers that identify the object + * type + * + * Initialize the private object, which can be embedded into any + * driver private object that needs its own atomic state. + */ +void +drm_atomic_private_obj_init(struct drm_private_obj *obj, + struct drm_private_state *state, + const struct drm_private_state_funcs *funcs) +{ + memset(obj, 0, sizeof(*obj)); + + obj->state = state; + obj->funcs = funcs; +} +EXPORT_SYMBOL(drm_atomic_private_obj_init); + +/** + * drm_atomic_private_obj_fini - finalize private object + * @obj: private object + * + * Finalize the private object. + */ +void +drm_atomic_private_obj_fini(struct drm_private_obj *obj) +{ + obj->funcs->atomic_destroy_state(obj, obj->state); +} +EXPORT_SYMBOL(drm_atomic_private_obj_fini); + +/** * drm_atomic_get_private_obj_state - get private object state * @state: global atomic state * @obj: private object to get the state for - * @funcs: pointer to the struct of function pointers that identify the object - * type * * This function returns the private object state for the given private object, * allocating the state if needed. It does not grab any locks as the caller is @@ -1014,19 +1049,21 @@ static void drm_atomic_plane_print_state(struct drm_printer *p, * * Either the allocated state or the error code encoded into a pointer. */ -void * -drm_atomic_get_private_obj_state(struct drm_atomic_state *state, void *obj, - const struct drm_private_state_funcs *funcs) +struct drm_private_state * +drm_atomic_get_private_obj_state(struct drm_atomic_state *state, + struct drm_private_obj *obj) { + const struct drm_private_state_funcs *funcs = obj->funcs; struct __drm_private_objs_state *p; + struct drm_private_state *obj_state; int index = state->num_private_objs; int ret, i;
for (i = 0; i < state->num_private_objs; i++) { p = __drm_atomic_state_private_obj(state, i);
- if (obj == p->obj) - return p->obj_state; + if (obj == p->ptr) + return p->state; }
ret = drm_dynarray_reserve(&state->private_objs, index); @@ -1035,19 +1072,22 @@ drm_atomic_get_private_obj_state(struct drm_atomic_state *state, void *obj,
p = __drm_atomic_state_private_obj(state, index);
- p->obj_state = funcs->duplicate_state(state, obj); - if (!p->obj_state) + obj_state = funcs->atomic_duplicate_state(obj); + if (!obj_state) return ERR_PTR(-ENOMEM);
- p->obj = obj; - p->funcs = funcs; + p->state = obj_state; + p->old_state = obj->state; + p->new_state = obj_state; + p->ptr = obj; + obj_state->state = state;
state->num_private_objs = index + 1;
- DRM_DEBUG_ATOMIC("Added new private object state %p to %p\n", - p->obj_state, state); + DRM_DEBUG_ATOMIC("Added new private object [%p] state %p to %p\n", + obj, obj_state, state);
- return p->obj_state; + return obj_state; } EXPORT_SYMBOL(drm_atomic_get_private_obj_state);
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 77b57cdf0460..bc7d3a5a50f7 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -2267,8 +2267,8 @@ void drm_atomic_helper_swap_state(struct drm_atomic_state *state, struct drm_plane *plane; struct drm_plane_state *old_plane_state, *new_plane_state; struct drm_crtc_commit *commit; - void *obj, *obj_state; - const struct drm_private_state_funcs *funcs; + struct drm_private_obj *obj; + struct drm_private_state *old_obj_state, *new_obj_state;
if (stall) { for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) { @@ -2330,8 +2330,15 @@ void drm_atomic_helper_swap_state(struct drm_atomic_state *state, plane->state = new_plane_state; }
- __for_each_private_obj(state, obj, obj_state, i, funcs) - funcs->swap_state(obj, &__drm_atomic_state_private_obj(state, i)->obj_state); + for_each_oldnew_private_obj_in_state(state, obj, old_obj_state, new_obj_state, i) { + WARN_ON(obj->state != old_obj_state); + + old_obj_state->state = state; + new_obj_state->state = NULL; + + __drm_atomic_state_private_obj(state, i)->state = old_obj_state; + obj->state = new_obj_state; + } } EXPORT_SYMBOL(drm_atomic_helper_swap_state);
@@ -3828,3 +3835,18 @@ int drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc, return ret; } EXPORT_SYMBOL(drm_atomic_helper_legacy_gamma_set); + +/** + * __drm_atomic_helper_private_duplicate_state - copy atomic private state + * @obj: CRTC object + * @state: new private object state + * + * Copies atomic state from a private objects's current state and resets inferred values. + * This is useful for drivers that subclass the private state. + */ +void __drm_atomic_helper_private_obj_duplicate_state(struct drm_private_obj *obj, + struct drm_private_state *state) +{ + memcpy(state, obj->state, sizeof(*state)); +} +EXPORT_SYMBOL(__drm_atomic_helper_private_obj_duplicate_state); diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c index bfd237c15e76..91510098f60e 100644 --- a/drivers/gpu/drm/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/drm_dp_mst_topology.c @@ -31,6 +31,8 @@ #include <drm/drmP.h>
#include <drm/drm_fixed.h> +#include <drm/drm_atomic.h> +#include <drm/drm_atomic_helper.h>
/** * DOC: dp mst helper @@ -2992,41 +2994,32 @@ static void drm_dp_destroy_connector_work(struct work_struct *work) (*mgr->cbs->hotplug)(mgr); }
-void *drm_dp_mst_duplicate_state(struct drm_atomic_state *state, void *obj) +static struct drm_private_state * +drm_dp_mst_duplicate_state(struct drm_private_obj *obj) { - struct drm_dp_mst_topology_mgr *mgr = obj; - struct drm_dp_mst_topology_state *new_mst_state; + struct drm_dp_mst_topology_state *state;
- if (WARN_ON(!mgr->state)) + state = kmemdup(obj->state, sizeof(*state), GFP_KERNEL); + if (!state) return NULL;
- new_mst_state = kmemdup(mgr->state, sizeof(*new_mst_state), GFP_KERNEL); - if (new_mst_state) - new_mst_state->state = state; - return new_mst_state; -} - -void drm_dp_mst_swap_state(void *obj, void **obj_state_ptr) -{ - struct drm_dp_mst_topology_mgr *mgr = obj; - struct drm_dp_mst_topology_state **topology_state_ptr; - - topology_state_ptr = (struct drm_dp_mst_topology_state **)obj_state_ptr; + __drm_atomic_helper_private_obj_duplicate_state(obj, &state->base);
- mgr->state->state = (*topology_state_ptr)->state; - swap(*topology_state_ptr, mgr->state); - mgr->state->state = NULL; + return &state->base; }
-void drm_dp_mst_destroy_state(void *obj_state) +static void drm_dp_mst_destroy_state(struct drm_private_obj *obj, + struct drm_private_state *state) { - kfree(obj_state); + struct drm_dp_mst_topology_state *mst_state = + to_dp_mst_topology_state(state); + + kfree(mst_state); }
static const struct drm_private_state_funcs mst_state_funcs = { - .duplicate_state = drm_dp_mst_duplicate_state, - .swap_state = drm_dp_mst_swap_state, - .destroy_state = drm_dp_mst_destroy_state, + .atomic_duplicate_state = drm_dp_mst_duplicate_state, + .atomic_destroy_state = drm_dp_mst_destroy_state, };
/** @@ -3050,8 +3043,7 @@ struct drm_dp_mst_topology_state *drm_atomic_get_mst_topology_state(struct drm_a struct drm_device *dev = mgr->dev;
WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex)); - return drm_atomic_get_private_obj_state(state, mgr, - &mst_state_funcs); + return to_dp_mst_topology_state(drm_atomic_get_private_obj_state(state, &mgr->base)); } EXPORT_SYMBOL(drm_atomic_get_mst_topology_state);
@@ -3071,6 +3063,8 @@ int drm_dp_mst_topology_mgr_init(struct drm_dp_mst_topology_mgr *mgr, int max_dpcd_transaction_bytes, int max_payloads, int conn_base_id) { + struct drm_dp_mst_topology_state *mst_state; + mutex_init(&mgr->lock); mutex_init(&mgr->qlock); mutex_init(&mgr->payload_lock); @@ -3099,14 +3093,18 @@ int drm_dp_mst_topology_mgr_init(struct drm_dp_mst_topology_mgr *mgr, if (test_calc_pbn_mode() < 0) DRM_ERROR("MST PBN self-test failed\n");
- mgr->state = kzalloc(sizeof(*mgr->state), GFP_KERNEL); - if (mgr->state == NULL) + mst_state = kzalloc(sizeof(*mst_state), GFP_KERNEL); + if (mst_state == NULL) return -ENOMEM; - mgr->state->mgr = mgr; + + mst_state->mgr = mgr;
/* max. time slots - one slot for MTP header */ - mgr->state->avail_slots = 63; - mgr->funcs = &mst_state_funcs; + mst_state->avail_slots = 63; + + drm_atomic_private_obj_init(&mgr->base, + &mst_state->base, + &mst_state_funcs);
return 0; } @@ -3128,8 +3126,7 @@ void drm_dp_mst_topology_mgr_destroy(struct drm_dp_mst_topology_mgr *mgr) mutex_unlock(&mgr->payload_lock); mgr->dev = NULL; mgr->aux = NULL; - kfree(mgr->state); - mgr->state = NULL; + drm_atomic_private_obj_fini(&mgr->base); mgr->funcs = NULL; } EXPORT_SYMBOL(drm_dp_mst_topology_mgr_destroy); diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h index 809e8b4c3719..addec49a14bf 100644 --- a/include/drm/drm_atomic.h +++ b/include/drm/drm_atomic.h @@ -155,6 +155,9 @@ struct __drm_connectors_state { struct drm_connector_state *state, *old_state, *new_state; };
+struct drm_private_obj; +struct drm_private_state; + /** * struct drm_private_state_funcs - atomic state functions for private objects * @@ -167,7 +170,7 @@ struct __drm_connectors_state { */ struct drm_private_state_funcs { /** - * @duplicate_state: + * @atomic_duplicate_state: * * Duplicate the current state of the private object and return it. It * is an error to call this before obj->state has been initialized. @@ -177,29 +180,30 @@ struct drm_private_state_funcs { * Duplicated atomic state or NULL when obj->state is not * initialized or allocation failed. */ - void *(*duplicate_state)(struct drm_atomic_state *state, void *obj); + struct drm_private_state *(*atomic_duplicate_state)(struct drm_private_obj *obj);
/** - * @swap_state: + * @atomic_destroy_state: * - * This function swaps the existing state of a private object @obj with - * it's newly created state, the pointer to which is passed as - * @obj_state_ptr. + * Frees the private object state created with @atomic_duplicate_state. */ - void (*swap_state)(void *obj, void **obj_state_ptr); + void (*atomic_destroy_state)(struct drm_private_obj *obj, + struct drm_private_state *state); +};
- /** - * @destroy_state: - * - * Frees the private object state created with @duplicate_state. - */ - void (*destroy_state)(void *obj_state); +struct drm_private_obj { + struct drm_private_state *state; + + const struct drm_private_state_funcs *funcs; +}; + +struct drm_private_state { + struct drm_atomic_state *state; };
struct __drm_private_objs_state { - void *obj; - void *obj_state; - const struct drm_private_state_funcs *funcs; + struct drm_private_obj *ptr; + struct drm_private_state *state, *old_state, *new_state; };
/** @@ -336,10 +340,14 @@ int drm_atomic_connector_set_property(struct drm_connector *connector, struct drm_connector_state *state, struct drm_property *property, uint64_t val);
-void * __must_check +void drm_atomic_private_obj_init(struct drm_private_obj *obj, + struct drm_private_state *state, + const struct drm_private_state_funcs *funcs); +void drm_atomic_private_obj_fini(struct drm_private_obj *obj); + +struct drm_private_state * __must_check drm_atomic_get_private_obj_state(struct drm_atomic_state *state, - void *obj, - const struct drm_private_state_funcs *funcs); + struct drm_private_obj *obj);
/** * drm_atomic_get_existing_crtc_state - get crtc state, if it exists @@ -826,43 +834,66 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p); for_each_if (plane)
/** - * __for_each_private_obj - iterate over all private objects + * for_each_oldnew_private_obj_in_state - iterate over all private objects in an atomic update * @__state: &struct drm_atomic_state pointer - * @obj: private object iteration cursor - * @obj_state: private object state iteration cursor + * @obj: &struct drm_private_obj iteration cursor + * @old_obj_state: &struct drm_private_state iteration cursor for the old state + * @new_obj_state: &struct drm_private_state iteration cursor for the new state * @__i: int iteration cursor, for macro-internal use - * @__funcs: &struct drm_private_state_funcs iteration cursor * - * This macro iterates over the array containing private object data in atomic - * state + * This iterates over all private objects in an atomic update, tracking both + * old and new state. This is useful in places where the state delta needs + * to be considered, for example in atomic check functions. */ -#define __for_each_private_obj(__state, obj, obj_state, __i, __funcs) \ - for ((__i) = 0; \ - (__i) < (__state)->num_private_objs && \ - ((obj) = __drm_atomic_state_private_obj(__state, __i)->obj, \ - (__funcs) = __drm_atomic_state_private_obj(__state, __i)->funcs, \ - (obj_state) = __drm_atomic_state_private_obj(__state, __i)->obj_state, \ - 1); \ - (__i)++) \ +#define for_each_oldnew_private_obj_in_state(__state, obj, old_obj_state, new_obj_state, __i) \ + for ((__i) = 0; \ + (__i) < (__state)->num_private_objs && \ + ((obj) = __drm_atomic_state_private_obj(__state, __i)->ptr, \ + (old_obj_state) = __drm_atomic_state_private_obj(__state, __i)->old_state, \ + (new_obj_state) = __drm_atomic_state_private_obj(__state, __i)->new_state, 1); \ + (__i)++) \ + for_each_if (obj) +
/** - * for_each_private_obj - iterate over a specify type of private object + * for_each_old_private_obj_in_state - iterate over all private objects in an atomic update * @__state: &struct drm_atomic_state pointer - * @obj_funcs: &struct drm_private_state_funcs function table to filter - * private objects - * @obj: private object iteration cursor - * @obj_state: private object state iteration cursor + * @obj: &struct drm_private_obj iteration cursor + * @old_obj_state: &struct drm_private_state iteration cursor for the old state * @__i: int iteration cursor, for macro-internal use - * @__funcs: &struct drm_private_state_funcs iteration cursor * - * This macro iterates over the private objects state array while filtering the - * objects based on the vfunc table that is passed as @obj_funcs. New macros - * can be created by passing in the vfunc table associated with a specific - * private object. + * This iterates over all private objects in an atomic update, tracking only + * the old state. This is useful in disable functions, where we need the old + * state the hardware is still in. */ -#define for_each_private_obj(__state, obj_funcs, obj, obj_state, __i, __funcs) \ - __for_each_private_obj(__state, obj, obj_state, __i, __funcs) \ - for_each_if (__funcs == obj_funcs) +#define for_each_old_private_obj_in_state(__state, obj, old_obj_state, __i) \ + for ((__i) = 0; \ + (__i) < (__state)->num_private_objs && \ + ((obj) = __drm_atomic_state_private_obj(__state, __i)->ptr, \ + (old_obj_state) = __drm_atomic_state_private_obj(__state, __i)->old_state, 1); \ + (__i)++) \ + for_each_if (obj) + + +/** + * for_each_new_private_obj_in_state - iterate over all private objects in an atomic update + * @__state: &struct drm_atomic_state pointer + * @obj: &struct drm_private_obj iteration cursor + * @new_obj_state: &struct drm_private_state iteration cursor for the new state + * @__i: int iteration cursor, for macro-internal use + * + * This iterates over all private objects in an atomic update, tracking only + * the new state. This is useful in enable functions, where we need the new state the + * hardware should be in when the atomic commit operation has completed. + */ +#define for_each_new_private_obj_in_state(__state, obj, new_obj_state, __i) \ + for ((__i) = 0; \ + (__i) < (__state)->num_private_objs && \ + ((obj) = __drm_atomic_state_private_obj(__state, __i)->ptr, \ + (new_obj_state) = __drm_atomic_state_private_obj(__state, __i)->new_state, 1); \ + (__i)++) \ + for_each_if (obj) +
/** * drm_atomic_crtc_needs_modeset - compute combined modeset need diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h index dd196cc0afd7..7db3438ff735 100644 --- a/include/drm/drm_atomic_helper.h +++ b/include/drm/drm_atomic_helper.h @@ -33,6 +33,8 @@ #include <drm/drm_modeset_helper.h>
struct drm_atomic_state; +struct drm_private_obj; +struct drm_private_state;
int drm_atomic_helper_check_modeset(struct drm_device *dev, struct drm_atomic_state *state); @@ -185,6 +187,8 @@ int drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green, u16 *blue, uint32_t size, struct drm_modeset_acquire_ctx *ctx); +void __drm_atomic_helper_private_obj_duplicate_state(struct drm_private_obj *obj, + struct drm_private_state *state);
/** * drm_atomic_crtc_for_each_plane - iterate over planes currently attached to CRTC diff --git a/include/drm/drm_dp_mst_helper.h b/include/drm/drm_dp_mst_helper.h index 177ab6f86855..d55abb75f29a 100644 --- a/include/drm/drm_dp_mst_helper.h +++ b/include/drm/drm_dp_mst_helper.h @@ -404,12 +404,17 @@ struct drm_dp_payload { int vcpi; };
+#define to_dp_mst_topology_state(x) container_of(x, struct drm_dp_mst_topology_state, base) + struct drm_dp_mst_topology_state { + struct drm_private_state base; int avail_slots; struct drm_atomic_state *state; struct drm_dp_mst_topology_mgr *mgr; };
+#define to_dp_mst_topology_mgr(x) container_of(x, struct drm_dp_mst_topology_mgr, base) + /** * struct drm_dp_mst_topology_mgr - DisplayPort MST manager * @@ -419,6 +424,11 @@ struct drm_dp_mst_topology_state { */ struct drm_dp_mst_topology_mgr { /** + * @base: Base private object for atomic + */ + struct drm_private_obj base; + + /** * @dev: device pointer for adding i2c devices etc. */ struct drm_device *dev;
From: Ville Syrjälä ville.syrjala@linux.intel.com
We'll be wanting to duplicate other states besides the one pointed to by crtc->state & co., so pass the duplicated state in explicitly.
@r@ identifier F =~ "^__drm_atomic_helper_.*_duplicate_state$"; identifier O, S; type T, TS; @@ F(T O, TS *S + ,const TS *old_state ) { <... - O->state + old_state ...> }
@@ identifier r.F; expression E; @@ F(E, ... + ,E->state )
Signed-off-by: Ville Syrjälä ville.syrjala@linux.intel.com --- drivers/gpu/drm/arm/malidp_crtc.c | 3 ++- drivers/gpu/drm/arm/malidp_planes.c | 3 ++- drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c | 3 ++- drivers/gpu/drm/drm_atomic_helper.c | 30 ++++++++++++++++---------- drivers/gpu/drm/drm_dp_mst_topology.c | 3 ++- drivers/gpu/drm/exynos/exynos_drm_plane.c | 3 ++- drivers/gpu/drm/i915/intel_atomic.c | 6 ++++-- drivers/gpu/drm/i915/intel_atomic_plane.c | 2 +- drivers/gpu/drm/i915/intel_sdvo.c | 4 +++- drivers/gpu/drm/imx/ipuv3-crtc.c | 3 ++- drivers/gpu/drm/imx/ipuv3-plane.c | 3 ++- drivers/gpu/drm/mediatek/mtk_drm_crtc.c | 3 ++- drivers/gpu/drm/mediatek/mtk_drm_plane.c | 3 ++- drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c | 3 ++- drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c | 3 ++- drivers/gpu/drm/nouveau/nouveau_connector.c | 3 ++- drivers/gpu/drm/nouveau/nv50_display.c | 6 ++++-- drivers/gpu/drm/rcar-du/rcar_du_plane.c | 3 ++- drivers/gpu/drm/rcar-du/rcar_du_vsp.c | 3 ++- drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 3 ++- drivers/gpu/drm/tegra/dc.c | 6 ++++-- drivers/gpu/drm/tegra/dsi.c | 3 ++- drivers/gpu/drm/tegra/sor.c | 3 ++- drivers/gpu/drm/vc4/vc4_crtc.c | 3 ++- drivers/gpu/drm/vc4/vc4_plane.c | 3 ++- drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 7 +++--- include/drm/drm_atomic_helper.h | 12 +++++++---- 27 files changed, 85 insertions(+), 45 deletions(-)
diff --git a/drivers/gpu/drm/arm/malidp_crtc.c b/drivers/gpu/drm/arm/malidp_crtc.c index 3615d18a7ddf..037514f42a83 100644 --- a/drivers/gpu/drm/arm/malidp_crtc.c +++ b/drivers/gpu/drm/arm/malidp_crtc.c @@ -427,7 +427,8 @@ static struct drm_crtc_state *malidp_crtc_duplicate_state(struct drm_crtc *crtc) if (!state) return NULL;
- __drm_atomic_helper_crtc_duplicate_state(crtc, &state->base); + __drm_atomic_helper_crtc_duplicate_state(crtc, &state->base, + crtc->state); memcpy(state->gamma_coeffs, old_state->gamma_coeffs, sizeof(state->gamma_coeffs)); memcpy(state->coloradj_coeffs, old_state->coloradj_coeffs, diff --git a/drivers/gpu/drm/arm/malidp_planes.c b/drivers/gpu/drm/arm/malidp_planes.c index 600fa7bd7f52..fe744396bc99 100644 --- a/drivers/gpu/drm/arm/malidp_planes.c +++ b/drivers/gpu/drm/arm/malidp_planes.c @@ -98,7 +98,8 @@ drm_plane_state *malidp_duplicate_plane_state(struct drm_plane *plane) return NULL;
m_state = to_malidp_plane_state(plane->state); - __drm_atomic_helper_plane_duplicate_state(plane, &state->base); + __drm_atomic_helper_plane_duplicate_state(plane, &state->base, + plane->state); state->rotmem_size = m_state->rotmem_size; state->format = m_state->format; state->n_planes = m_state->n_planes; diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c index 441769c5bcd4..bb7c5eb9526a 100644 --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c @@ -385,7 +385,8 @@ atmel_hlcdc_crtc_duplicate_state(struct drm_crtc *crtc) state = kmalloc(sizeof(*state), GFP_KERNEL); if (!state) return NULL; - __drm_atomic_helper_crtc_duplicate_state(crtc, &state->base); + __drm_atomic_helper_crtc_duplicate_state(crtc, &state->base, + crtc->state);
cur = drm_crtc_state_to_atmel_hlcdc_crtc_state(crtc->state); state->output_mode = cur->output_mode; diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index bc7d3a5a50f7..0745a08a6cc2 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -3374,9 +3374,10 @@ EXPORT_SYMBOL(drm_atomic_helper_crtc_reset); * This is useful for drivers that subclass the CRTC state. */ void __drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc, - struct drm_crtc_state *state) + struct drm_crtc_state *state, + const struct drm_crtc_state *old_state) { - memcpy(state, crtc->state, sizeof(*state)); + memcpy(state, old_state, sizeof(*state));
if (state->mode_blob) drm_property_blob_get(state->mode_blob); @@ -3414,7 +3415,8 @@ drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc)
state = kmalloc(sizeof(*state), GFP_KERNEL); if (state) - __drm_atomic_helper_crtc_duplicate_state(crtc, state); + __drm_atomic_helper_crtc_duplicate_state(crtc, state, + crtc->state);
return state; } @@ -3484,9 +3486,10 @@ EXPORT_SYMBOL(drm_atomic_helper_plane_reset); * drivers that subclass the plane state. */ void __drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane, - struct drm_plane_state *state) + struct drm_plane_state *state, + const struct drm_plane_state *old_state) { - memcpy(state, plane->state, sizeof(*state)); + memcpy(state, old_state, sizeof(*state));
if (state->fb) drm_framebuffer_get(state->fb); @@ -3512,7 +3515,8 @@ drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane)
state = kmalloc(sizeof(*state), GFP_KERNEL); if (state) - __drm_atomic_helper_plane_duplicate_state(plane, state); + __drm_atomic_helper_plane_duplicate_state(plane, state, + plane->state);
return state; } @@ -3606,9 +3610,10 @@ EXPORT_SYMBOL(drm_atomic_helper_connector_reset); */ void __drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector, - struct drm_connector_state *state) + struct drm_connector_state *state, + const struct drm_connector_state *old_state) { - memcpy(state, connector->state, sizeof(*state)); + memcpy(state, old_state, sizeof(*state)); if (state->crtc) drm_connector_get(connector); } @@ -3631,7 +3636,9 @@ drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector)
state = kmalloc(sizeof(*state), GFP_KERNEL); if (state) - __drm_atomic_helper_connector_duplicate_state(connector, state); + __drm_atomic_helper_connector_duplicate_state(connector, + state, + connector->state);
return state; } @@ -3845,8 +3852,9 @@ EXPORT_SYMBOL(drm_atomic_helper_legacy_gamma_set); * This is useful for drivers that subclass the private state. */ void __drm_atomic_helper_private_obj_duplicate_state(struct drm_private_obj *obj, - struct drm_private_state *state) + struct drm_private_state *state, + const struct drm_private_state *old_state) { - memcpy(state, obj->state, sizeof(*state)); + memcpy(state, old_state, sizeof(*state)); } EXPORT_SYMBOL(__drm_atomic_helper_private_obj_duplicate_state); diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c index 91510098f60e..140c24258b7b 100644 --- a/drivers/gpu/drm/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/drm_dp_mst_topology.c @@ -3003,7 +3003,8 @@ drm_dp_mst_duplicate_state(struct drm_private_obj *obj) if (!state) return NULL;
- __drm_atomic_helper_private_obj_duplicate_state(obj, &state->base); + __drm_atomic_helper_private_obj_duplicate_state(obj, &state->base, + obj->state);
return &state->base; } diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.c b/drivers/gpu/drm/exynos/exynos_drm_plane.c index 611b6fd65433..1807f4c7bcf6 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_plane.c +++ b/drivers/gpu/drm/exynos/exynos_drm_plane.c @@ -156,7 +156,8 @@ exynos_drm_plane_duplicate_state(struct drm_plane *plane) if (!copy) return NULL;
- __drm_atomic_helper_plane_duplicate_state(plane, ©->base); + __drm_atomic_helper_plane_duplicate_state(plane, ©->base, + plane->state); return ©->base; }
diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c index 36d4e635e4ce..e5d5a558c84a 100644 --- a/drivers/gpu/drm/i915/intel_atomic.c +++ b/drivers/gpu/drm/i915/intel_atomic.c @@ -146,7 +146,8 @@ intel_digital_connector_duplicate_state(struct drm_connector *connector) if (!state) return NULL;
- __drm_atomic_helper_connector_duplicate_state(connector, &state->base); + __drm_atomic_helper_connector_duplicate_state(connector, &state->base, + connector->state); return &state->base; }
@@ -168,7 +169,8 @@ intel_crtc_duplicate_state(struct drm_crtc *crtc) if (!crtc_state) return NULL;
- __drm_atomic_helper_crtc_duplicate_state(crtc, &crtc_state->base); + __drm_atomic_helper_crtc_duplicate_state(crtc, &crtc_state->base, + crtc->state);
crtc_state->update_pipe = false; crtc_state->disable_lp_wm = false; diff --git a/drivers/gpu/drm/i915/intel_atomic_plane.c b/drivers/gpu/drm/i915/intel_atomic_plane.c index 7cdbe9ae2c96..41a7354c14d3 100644 --- a/drivers/gpu/drm/i915/intel_atomic_plane.c +++ b/drivers/gpu/drm/i915/intel_atomic_plane.c @@ -83,7 +83,7 @@ intel_plane_duplicate_state(struct drm_plane *plane)
state = &intel_state->base;
- __drm_atomic_helper_plane_duplicate_state(plane, state); + __drm_atomic_helper_plane_duplicate_state(plane, state, plane->state);
intel_state->vma = NULL;
diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index f902922d4ae6..0d14807b38a5 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -2187,7 +2187,9 @@ intel_sdvo_connector_duplicate_state(struct drm_connector *connector) if (!state) return NULL;
- __drm_atomic_helper_connector_duplicate_state(connector, &state->base.base); + __drm_atomic_helper_connector_duplicate_state(connector, + &state->base.base, + connector->state); return &state->base.base; }
diff --git a/drivers/gpu/drm/imx/ipuv3-crtc.c b/drivers/gpu/drm/imx/ipuv3-crtc.c index 53e0b24beda6..44598b6a5cfc 100644 --- a/drivers/gpu/drm/imx/ipuv3-crtc.c +++ b/drivers/gpu/drm/imx/ipuv3-crtc.c @@ -137,7 +137,8 @@ static struct drm_crtc_state *imx_drm_crtc_duplicate_state(struct drm_crtc *crtc if (!state) return NULL;
- __drm_atomic_helper_crtc_duplicate_state(crtc, &state->base); + __drm_atomic_helper_crtc_duplicate_state(crtc, &state->base, + crtc->state);
WARN_ON(state->base.crtc != crtc); state->base.crtc = crtc; diff --git a/drivers/gpu/drm/imx/ipuv3-plane.c b/drivers/gpu/drm/imx/ipuv3-plane.c index 49546222c6d3..3b3c979c4f6d 100644 --- a/drivers/gpu/drm/imx/ipuv3-plane.c +++ b/drivers/gpu/drm/imx/ipuv3-plane.c @@ -288,7 +288,8 @@ struct drm_plane_state *ipu_plane_duplicate_state(struct drm_plane *plane)
state = kmalloc(sizeof(*state), GFP_KERNEL); if (state) - __drm_atomic_helper_plane_duplicate_state(plane, &state->base); + __drm_atomic_helper_plane_duplicate_state(plane, &state->base, + plane->state);
return &state->base; } diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c index fc65c57dda8c..4bdc612fbe89 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c @@ -134,7 +134,8 @@ static struct drm_crtc_state *mtk_drm_crtc_duplicate_state(struct drm_crtc *crtc if (!state) return NULL;
- __drm_atomic_helper_crtc_duplicate_state(crtc, &state->base); + __drm_atomic_helper_crtc_duplicate_state(crtc, &state->base, + crtc->state);
WARN_ON(state->base.crtc != crtc); state->base.crtc = crtc; diff --git a/drivers/gpu/drm/mediatek/mtk_drm_plane.c b/drivers/gpu/drm/mediatek/mtk_drm_plane.c index e405e89ed5e5..9ecc23f67cc7 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_plane.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_plane.c @@ -59,7 +59,8 @@ static struct drm_plane_state *mtk_plane_duplicate_state(struct drm_plane *plane if (!state) return NULL;
- __drm_atomic_helper_plane_duplicate_state(plane, &state->base); + __drm_atomic_helper_plane_duplicate_state(plane, &state->base, + plane->state);
WARN_ON(state->base.plane != plane);
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c index 4322a502555a..49c7410d0ef6 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c @@ -901,7 +901,8 @@ mdp5_crtc_duplicate_state(struct drm_crtc *crtc) if (!mdp5_cstate) return NULL;
- __drm_atomic_helper_crtc_duplicate_state(crtc, &mdp5_cstate->base); + __drm_atomic_helper_crtc_duplicate_state(crtc, &mdp5_cstate->base, + crtc->state);
return &mdp5_cstate->base; } diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c index fe3a4de1a433..de00c9ad14fd 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c @@ -226,7 +226,8 @@ mdp5_plane_duplicate_state(struct drm_plane *plane) if (!mdp5_state) return NULL;
- __drm_atomic_helper_plane_duplicate_state(plane, &mdp5_state->base); + __drm_atomic_helper_plane_duplicate_state(plane, &mdp5_state->base, + plane->state);
return &mdp5_state->base; } diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index 147b22163f9f..dc1880eb00bf 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -234,7 +234,8 @@ nouveau_conn_atomic_duplicate_state(struct drm_connector *connector) struct nouveau_conn_atom *asyc; if (!(asyc = kmalloc(sizeof(*asyc), GFP_KERNEL))) return NULL; - __drm_atomic_helper_connector_duplicate_state(connector, &asyc->state); + __drm_atomic_helper_connector_duplicate_state(connector, &asyc->state, + connector->state); asyc->dither = armc->dither; asyc->scaler = armc->scaler; asyc->procamp = armc->procamp; diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index 42a85c14aea0..6ca8d97e7dbc 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -1011,7 +1011,8 @@ nv50_wndw_atomic_duplicate_state(struct drm_plane *plane) struct nv50_wndw_atom *asyw; if (!(asyw = kmalloc(sizeof(*asyw), GFP_KERNEL))) return NULL; - __drm_atomic_helper_plane_duplicate_state(plane, &asyw->state); + __drm_atomic_helper_plane_duplicate_state(plane, &asyw->state, + plane->state); asyw->interval = 1; asyw->sema = armw->sema; asyw->ntfy = armw->ntfy; @@ -2263,7 +2264,8 @@ nv50_head_atomic_duplicate_state(struct drm_crtc *crtc) struct nv50_head_atom *asyh; if (!(asyh = kmalloc(sizeof(*asyh), GFP_KERNEL))) return NULL; - __drm_atomic_helper_crtc_duplicate_state(crtc, &asyh->state); + __drm_atomic_helper_crtc_duplicate_state(crtc, &asyh->state, + crtc->state); asyh->view = armh->view; asyh->mode = armh->mode; asyh->lut = armh->lut; diff --git a/drivers/gpu/drm/rcar-du/rcar_du_plane.c b/drivers/gpu/drm/rcar-du/rcar_du_plane.c index dcde6288da6c..a856507f5717 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_plane.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_plane.c @@ -623,7 +623,8 @@ rcar_du_plane_atomic_duplicate_state(struct drm_plane *plane) if (copy == NULL) return NULL;
- __drm_atomic_helper_plane_duplicate_state(plane, ©->state); + __drm_atomic_helper_plane_duplicate_state(plane, ©->state, + plane->state);
return ©->state; } diff --git a/drivers/gpu/drm/rcar-du/rcar_du_vsp.c b/drivers/gpu/drm/rcar-du/rcar_du_vsp.c index f870445ebc8d..21a30775edb7 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_vsp.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_vsp.c @@ -316,7 +316,8 @@ rcar_du_vsp_plane_atomic_duplicate_state(struct drm_plane *plane) if (copy == NULL) return NULL;
- __drm_atomic_helper_plane_duplicate_state(plane, ©->state); + __drm_atomic_helper_plane_duplicate_state(plane, ©->state, + plane->state);
return ©->state; } diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index ee876a9631f0..9f586f698e52 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -1112,7 +1112,8 @@ static struct drm_crtc_state *vop_crtc_duplicate_state(struct drm_crtc *crtc) if (!rockchip_state) return NULL;
- __drm_atomic_helper_crtc_duplicate_state(crtc, &rockchip_state->base); + __drm_atomic_helper_crtc_duplicate_state(crtc, &rockchip_state->base, + crtc->state); return &rockchip_state->base; }
diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c index 0cb9b90e2e68..d725115d011d 100644 --- a/drivers/gpu/drm/tegra/dc.c +++ b/drivers/gpu/drm/tegra/dc.c @@ -457,7 +457,8 @@ static struct drm_plane_state *tegra_plane_atomic_duplicate_state(struct drm_pla if (!copy) return NULL;
- __drm_atomic_helper_plane_duplicate_state(plane, ©->base); + __drm_atomic_helper_plane_duplicate_state(plane, ©->base, + plane->state); copy->tiling = state->tiling; copy->format = state->format; copy->swap = state->swap; @@ -1042,7 +1043,8 @@ tegra_crtc_atomic_duplicate_state(struct drm_crtc *crtc) if (!copy) return NULL;
- __drm_atomic_helper_crtc_duplicate_state(crtc, ©->base); + __drm_atomic_helper_crtc_duplicate_state(crtc, ©->base, + crtc->state); copy->clk = state->clk; copy->pclk = state->pclk; copy->div = state->div; diff --git a/drivers/gpu/drm/tegra/dsi.c b/drivers/gpu/drm/tegra/dsi.c index 3dea1216bafd..ce646493e939 100644 --- a/drivers/gpu/drm/tegra/dsi.c +++ b/drivers/gpu/drm/tegra/dsi.c @@ -809,7 +809,8 @@ tegra_dsi_connector_duplicate_state(struct drm_connector *connector) return NULL;
__drm_atomic_helper_connector_duplicate_state(connector, - ©->base); + ©->base, + connector->state);
return ©->base; } diff --git a/drivers/gpu/drm/tegra/sor.c b/drivers/gpu/drm/tegra/sor.c index a8f528925009..02c3439c2e96 100644 --- a/drivers/gpu/drm/tegra/sor.c +++ b/drivers/gpu/drm/tegra/sor.c @@ -1334,7 +1334,8 @@ tegra_sor_connector_duplicate_state(struct drm_connector *connector) if (!copy) return NULL;
- __drm_atomic_helper_connector_duplicate_state(connector, ©->base); + __drm_atomic_helper_connector_duplicate_state(connector, ©->base, + connector->state);
return ©->base; } diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c index 9e0c1500375c..28bdfb5adb9e 100644 --- a/drivers/gpu/drm/vc4/vc4_crtc.c +++ b/drivers/gpu/drm/vc4/vc4_crtc.c @@ -821,7 +821,8 @@ static struct drm_crtc_state *vc4_crtc_duplicate_state(struct drm_crtc *crtc) if (!vc4_state) return NULL;
- __drm_atomic_helper_crtc_duplicate_state(crtc, &vc4_state->base); + __drm_atomic_helper_crtc_duplicate_state(crtc, &vc4_state->base, + crtc->state); return &vc4_state->base; }
diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c index 8853e9a4f005..43b388a42c1e 100644 --- a/drivers/gpu/drm/vc4/vc4_plane.c +++ b/drivers/gpu/drm/vc4/vc4_plane.c @@ -187,7 +187,8 @@ static struct drm_plane_state *vc4_plane_duplicate_state(struct drm_plane *plane
memset(&vc4_state->lbm, 0, sizeof(vc4_state->lbm));
- __drm_atomic_helper_plane_duplicate_state(plane, &vc4_state->base); + __drm_atomic_helper_plane_duplicate_state(plane, &vc4_state->base, + plane->state);
if (vc4_state->dlist) { vc4_state->dlist = kmemdup(vc4_state->dlist, diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 1cd67b10a0d9..dc3b4a9e3d25 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -612,7 +612,7 @@ vmw_du_crtc_duplicate_state(struct drm_crtc *crtc)
state = &vcs->base;
- __drm_atomic_helper_crtc_duplicate_state(crtc, state); + __drm_atomic_helper_crtc_duplicate_state(crtc, state, crtc->state);
return state; } @@ -701,7 +701,7 @@ vmw_du_plane_duplicate_state(struct drm_plane *plane)
state = &vps->base;
- __drm_atomic_helper_plane_duplicate_state(plane, state); + __drm_atomic_helper_plane_duplicate_state(plane, state, plane->state);
return state; } @@ -796,7 +796,8 @@ vmw_du_connector_duplicate_state(struct drm_connector *connector)
state = &vcs->base;
- __drm_atomic_helper_connector_duplicate_state(connector, state); + __drm_atomic_helper_connector_duplicate_state(connector, state, + connector->state);
return state; } diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h index 7db3438ff735..0adacaca0941 100644 --- a/include/drm/drm_atomic_helper.h +++ b/include/drm/drm_atomic_helper.h @@ -152,7 +152,8 @@ drm_atomic_helper_best_encoder(struct drm_connector *connector); /* default implementations for state handling */ void drm_atomic_helper_crtc_reset(struct drm_crtc *crtc); void __drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc, - struct drm_crtc_state *state); + struct drm_crtc_state *state, + const struct drm_crtc_state *old_state); struct drm_crtc_state * drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc); void __drm_atomic_helper_crtc_destroy_state(struct drm_crtc_state *state); @@ -161,7 +162,8 @@ void drm_atomic_helper_crtc_destroy_state(struct drm_crtc *crtc,
void drm_atomic_helper_plane_reset(struct drm_plane *plane); void __drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane, - struct drm_plane_state *state); + struct drm_plane_state *state, + const struct drm_plane_state *old_state); struct drm_plane_state * drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane); void __drm_atomic_helper_plane_destroy_state(struct drm_plane_state *state); @@ -173,7 +175,8 @@ void __drm_atomic_helper_connector_reset(struct drm_connector *connector, void drm_atomic_helper_connector_reset(struct drm_connector *connector); void __drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector, - struct drm_connector_state *state); + struct drm_connector_state *state, + const struct drm_connector_state *old_state); struct drm_connector_state * drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector); struct drm_atomic_state * @@ -188,7 +191,8 @@ int drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc, uint32_t size, struct drm_modeset_acquire_ctx *ctx); void __drm_atomic_helper_private_obj_duplicate_state(struct drm_private_obj *obj, - struct drm_private_state *state); + struct drm_private_state *state, + const struct drm_private_state *old_state);
/** * drm_atomic_crtc_for_each_plane - iterate over planes currently attached to CRTC
From: Ville Syrjälä ville.syrjala@linux.intel.com
Rename the local 'old_state' variable to 'old_mali_state' to get it out of the way of some cocci refactoring.
Signed-off-by: Ville Syrjälä ville.syrjala@linux.intel.com --- drivers/gpu/drm/arm/malidp_crtc.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/drivers/gpu/drm/arm/malidp_crtc.c b/drivers/gpu/drm/arm/malidp_crtc.c index 037514f42a83..2a92cb066bea 100644 --- a/drivers/gpu/drm/arm/malidp_crtc.c +++ b/drivers/gpu/drm/arm/malidp_crtc.c @@ -417,23 +417,23 @@ static const struct drm_crtc_helper_funcs malidp_crtc_helper_funcs = {
static struct drm_crtc_state *malidp_crtc_duplicate_state(struct drm_crtc *crtc) { - struct malidp_crtc_state *state, *old_state; + struct malidp_crtc_state *state, *old_mali_state;
if (WARN_ON(!crtc->state)) return NULL;
- old_state = to_malidp_crtc_state(crtc->state); + old_mali_state = to_malidp_crtc_state(crtc->state); state = kmalloc(sizeof(*state), GFP_KERNEL); if (!state) return NULL;
__drm_atomic_helper_crtc_duplicate_state(crtc, &state->base, crtc->state); - memcpy(state->gamma_coeffs, old_state->gamma_coeffs, + memcpy(state->gamma_coeffs, old_mali_state->gamma_coeffs, sizeof(state->gamma_coeffs)); - memcpy(state->coloradj_coeffs, old_state->coloradj_coeffs, + memcpy(state->coloradj_coeffs, old_mali_state->coloradj_coeffs, sizeof(state->coloradj_coeffs)); - memcpy(&state->scaler_config, &old_state->scaler_config, + memcpy(&state->scaler_config, &old_mali_state->scaler_config, sizeof(state->scaler_config)); state->scaled_planes_mask = 0;
From: Ville Syrjälä ville.syrjala@linux.intel.com
Rename the local 'old_state' variable to 'old_mtk_state' to get it out of the way of some cocci refactoring.
Signed-off-by: Ville Syrjälä ville.syrjala@linux.intel.com --- drivers/gpu/drm/mediatek/mtk_drm_plane.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_plane.c b/drivers/gpu/drm/mediatek/mtk_drm_plane.c index 9ecc23f67cc7..67c7bd17e350 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_plane.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_plane.c @@ -52,7 +52,7 @@ static void mtk_plane_reset(struct drm_plane *plane)
static struct drm_plane_state *mtk_plane_duplicate_state(struct drm_plane *plane) { - struct mtk_plane_state *old_state = to_mtk_plane_state(plane->state); + struct mtk_plane_state *old_mtk_state = to_mtk_plane_state(plane->state); struct mtk_plane_state *state;
state = kzalloc(sizeof(*state), GFP_KERNEL); @@ -64,7 +64,7 @@ static struct drm_plane_state *mtk_plane_duplicate_state(struct drm_plane *plane
WARN_ON(state->base.plane != plane);
- state->pending = old_state->pending; + state->pending = old_mtk_state->pending;
return &state->base; }
From: Ville Syrjälä ville.syrjala@linux.intel.com
We'll be wanting to duplicate other states besides the one pointed to by crtc->state & co., so pass the duplicated state in explicitly.
I wanted to make the old_state const, but that would have results in tons of new warnings because some drivers have their to_foo_state()s as static inlines. So I decided to leave old_state as non-const in the end.
@r@ identifier F =~ "^[^_].*duplicate_.*state$"; identifier I; type TO, TS; @@ TS F(TO I + ,TS old_state ) { <... - I->state + old_state ...> }
@@ identifier r.F; expression E; @@ F(E + ,E->state )
@@ type r.TO; type r.TS; type TF; identifier I; @@ TF { ... TS (*atomic_duplicate_state)(TO I + ,TS old_state ); ... };
@@ expression X, E; @@ X->atomic_duplicate_state(E + ,E->state )
Signed-off-by: Ville Syrjälä ville.syrjala@linux.intel.com --- drivers/gpu/drm/arm/malidp_crtc.c | 9 +++++---- drivers/gpu/drm/arm/malidp_planes.c | 9 +++++---- drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c | 9 +++++---- drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c | 5 +++-- drivers/gpu/drm/drm_atomic.c | 10 ++++++---- drivers/gpu/drm/drm_atomic_helper.c | 21 ++++++++++++--------- drivers/gpu/drm/drm_crtc_helper.c | 12 ++++++++---- drivers/gpu/drm/drm_dp_mst_topology.c | 7 ++++--- drivers/gpu/drm/drm_plane_helper.c | 12 ++++++++---- drivers/gpu/drm/exynos/exynos_drm_plane.c | 7 ++++--- drivers/gpu/drm/i915/intel_atomic.c | 14 ++++++++------ drivers/gpu/drm/i915/intel_atomic_plane.c | 7 ++++--- drivers/gpu/drm/i915/intel_display.c | 2 +- drivers/gpu/drm/i915/intel_drv.h | 9 ++++++--- drivers/gpu/drm/i915/intel_sdvo.c | 7 ++++--- drivers/gpu/drm/imx/ipuv3-crtc.c | 5 +++-- drivers/gpu/drm/imx/ipuv3-plane.c | 7 ++++--- drivers/gpu/drm/mediatek/mtk_drm_crtc.c | 5 +++-- drivers/gpu/drm/mediatek/mtk_drm_plane.c | 7 ++++--- drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c | 9 +++++---- drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c | 13 +++++++------ drivers/gpu/drm/nouveau/nouveau_connector.c | 7 ++++--- drivers/gpu/drm/nouveau/nouveau_connector.h | 3 ++- drivers/gpu/drm/nouveau/nv50_display.c | 14 ++++++++------ drivers/gpu/drm/rcar-du/rcar_du_plane.c | 9 +++++---- drivers/gpu/drm/rcar-du/rcar_du_vsp.c | 9 +++++---- drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 5 +++-- drivers/gpu/drm/tegra/dc.c | 14 ++++++++------ drivers/gpu/drm/tegra/dsi.c | 7 ++++--- drivers/gpu/drm/tegra/sor.c | 7 ++++--- drivers/gpu/drm/vc4/vc4_crtc.c | 5 +++-- drivers/gpu/drm/vc4/vc4_plane.c | 9 +++++---- drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 25 ++++++++++++++----------- drivers/gpu/drm/vmwgfx/vmwgfx_kms.h | 9 ++++++--- include/drm/drm_atomic.h | 3 ++- include/drm/drm_atomic_helper.h | 9 ++++++--- include/drm/drm_connector.h | 3 ++- include/drm/drm_crtc.h | 3 ++- include/drm/drm_plane.h | 3 ++- 39 files changed, 194 insertions(+), 136 deletions(-)
diff --git a/drivers/gpu/drm/arm/malidp_crtc.c b/drivers/gpu/drm/arm/malidp_crtc.c index 2a92cb066bea..8c78cb13b23b 100644 --- a/drivers/gpu/drm/arm/malidp_crtc.c +++ b/drivers/gpu/drm/arm/malidp_crtc.c @@ -415,20 +415,21 @@ static const struct drm_crtc_helper_funcs malidp_crtc_helper_funcs = { .atomic_disable = malidp_crtc_atomic_disable, };
-static struct drm_crtc_state *malidp_crtc_duplicate_state(struct drm_crtc *crtc) +static struct drm_crtc_state *malidp_crtc_duplicate_state(struct drm_crtc *crtc, + struct drm_crtc_state *old_state) { struct malidp_crtc_state *state, *old_mali_state;
- if (WARN_ON(!crtc->state)) + if (WARN_ON(!old_state)) return NULL;
- old_mali_state = to_malidp_crtc_state(crtc->state); + old_mali_state = to_malidp_crtc_state(old_state); state = kmalloc(sizeof(*state), GFP_KERNEL); if (!state) return NULL;
__drm_atomic_helper_crtc_duplicate_state(crtc, &state->base, - crtc->state); + old_state); memcpy(state->gamma_coeffs, old_mali_state->gamma_coeffs, sizeof(state->gamma_coeffs)); memcpy(state->coloradj_coeffs, old_mali_state->coloradj_coeffs, diff --git a/drivers/gpu/drm/arm/malidp_planes.c b/drivers/gpu/drm/arm/malidp_planes.c index fe744396bc99..33b0c07ad3a3 100644 --- a/drivers/gpu/drm/arm/malidp_planes.c +++ b/drivers/gpu/drm/arm/malidp_planes.c @@ -86,20 +86,21 @@ static void malidp_plane_reset(struct drm_plane *plane) }
static struct -drm_plane_state *malidp_duplicate_plane_state(struct drm_plane *plane) +drm_plane_state *malidp_duplicate_plane_state(struct drm_plane *plane, + struct drm_plane_state *old_state) { struct malidp_plane_state *state, *m_state;
- if (!plane->state) + if (!old_state) return NULL;
state = kmalloc(sizeof(*state), GFP_KERNEL); if (!state) return NULL;
- m_state = to_malidp_plane_state(plane->state); + m_state = to_malidp_plane_state(old_state); __drm_atomic_helper_plane_duplicate_state(plane, &state->base, - plane->state); + old_state); state->rotmem_size = m_state->rotmem_size; state->format = m_state->format; state->n_planes = m_state->n_planes; diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c index bb7c5eb9526a..cabba730c79a 100644 --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c @@ -375,20 +375,21 @@ static void atmel_hlcdc_crtc_reset(struct drm_crtc *crtc) }
static struct drm_crtc_state * -atmel_hlcdc_crtc_duplicate_state(struct drm_crtc *crtc) +atmel_hlcdc_crtc_duplicate_state(struct drm_crtc *crtc, + struct drm_crtc_state *old_state) { struct atmel_hlcdc_crtc_state *state, *cur;
- if (WARN_ON(!crtc->state)) + if (WARN_ON(!old_state)) return NULL;
state = kmalloc(sizeof(*state), GFP_KERNEL); if (!state) return NULL; __drm_atomic_helper_crtc_duplicate_state(crtc, &state->base, - crtc->state); + old_state);
- cur = drm_crtc_state_to_atmel_hlcdc_crtc_state(crtc->state); + cur = drm_crtc_state_to_atmel_hlcdc_crtc_state(old_state); state->output_mode = cur->output_mode;
return &state->base; diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c index b5bd9b005225..2ebf5c632a7a 100644 --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c @@ -1009,10 +1009,11 @@ static void atmel_hlcdc_plane_reset(struct drm_plane *p) }
static struct drm_plane_state * -atmel_hlcdc_plane_atomic_duplicate_state(struct drm_plane *p) +atmel_hlcdc_plane_atomic_duplicate_state(struct drm_plane *p, + struct drm_plane_state *old_state) { struct atmel_hlcdc_plane_state *state = - drm_plane_state_to_atmel_hlcdc_plane_state(p->state); + drm_plane_state_to_atmel_hlcdc_plane_state(old_state); struct atmel_hlcdc_plane_state *copy;
copy = kmemdup(state, sizeof(*state), GFP_KERNEL); diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index da7752230e4c..b1983e7b65d2 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -294,7 +294,7 @@ drm_atomic_get_crtc_state(struct drm_atomic_state *state, if (ret) return ERR_PTR(ret);
- crtc_state = crtc->funcs->atomic_duplicate_state(crtc); + crtc_state = crtc->funcs->atomic_duplicate_state(crtc, crtc->state); if (!crtc_state) return ERR_PTR(-ENOMEM);
@@ -709,7 +709,8 @@ drm_atomic_get_plane_state(struct drm_atomic_state *state, if (ret) return ERR_PTR(ret);
- plane_state = plane->funcs->atomic_duplicate_state(plane); + plane_state = plane->funcs->atomic_duplicate_state(plane, + plane->state); if (!plane_state) return ERR_PTR(-ENOMEM);
@@ -1072,7 +1073,7 @@ drm_atomic_get_private_obj_state(struct drm_atomic_state *state,
p = __drm_atomic_state_private_obj(state, index);
- obj_state = funcs->atomic_duplicate_state(obj); + obj_state = funcs->atomic_duplicate_state(obj, obj->state); if (!obj_state) return ERR_PTR(-ENOMEM);
@@ -1133,7 +1134,8 @@ drm_atomic_get_connector_state(struct drm_atomic_state *state, if (c->state) return c->state;
- connector_state = connector->funcs->atomic_duplicate_state(connector); + connector_state = connector->funcs->atomic_duplicate_state(connector, + connector->state); if (!connector_state) return ERR_PTR(-ENOMEM);
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 0745a08a6cc2..c60fb6289276 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -3406,17 +3406,18 @@ EXPORT_SYMBOL(__drm_atomic_helper_crtc_duplicate_state); * subclassed CRTC state structure. */ struct drm_crtc_state * -drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc) +drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc, + struct drm_crtc_state *old_state) { struct drm_crtc_state *state;
- if (WARN_ON(!crtc->state)) + if (WARN_ON(!old_state)) return NULL;
state = kmalloc(sizeof(*state), GFP_KERNEL); if (state) __drm_atomic_helper_crtc_duplicate_state(crtc, state, - crtc->state); + old_state);
return state; } @@ -3506,17 +3507,18 @@ EXPORT_SYMBOL(__drm_atomic_helper_plane_duplicate_state); * subclassed plane state structure. */ struct drm_plane_state * -drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane) +drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane, + struct drm_plane_state *old_state) { struct drm_plane_state *state;
- if (WARN_ON(!plane->state)) + if (WARN_ON(!old_state)) return NULL;
state = kmalloc(sizeof(*state), GFP_KERNEL); if (state) __drm_atomic_helper_plane_duplicate_state(plane, state, - plane->state); + old_state);
return state; } @@ -3627,18 +3629,19 @@ EXPORT_SYMBOL(__drm_atomic_helper_connector_duplicate_state); * subclassed connector state structure. */ struct drm_connector_state * -drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector) +drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector, + struct drm_connector_state *old_state) { struct drm_connector_state *state;
- if (WARN_ON(!connector->state)) + if (WARN_ON(!old_state)) return NULL;
state = kmalloc(sizeof(*state), GFP_KERNEL); if (state) __drm_atomic_helper_connector_duplicate_state(connector, state, - connector->state); + old_state);
return state; } diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index 4afdf7902eda..d0806c5cc472 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -1011,12 +1011,14 @@ int drm_helper_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mod int ret;
if (crtc->funcs->atomic_duplicate_state) - crtc_state = crtc->funcs->atomic_duplicate_state(crtc); + crtc_state = crtc->funcs->atomic_duplicate_state(crtc, + crtc->state); else { if (!crtc->state) drm_atomic_helper_crtc_reset(crtc);
- crtc_state = drm_atomic_helper_crtc_duplicate_state(crtc); + crtc_state = drm_atomic_helper_crtc_duplicate_state(crtc, + crtc->state); }
if (!crtc_state) @@ -1074,12 +1076,14 @@ int drm_helper_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, struct drm_plane *plane = crtc->primary;
if (plane->funcs->atomic_duplicate_state) - plane_state = plane->funcs->atomic_duplicate_state(plane); + plane_state = plane->funcs->atomic_duplicate_state(plane, + plane->state); else { if (!plane->state) drm_atomic_helper_plane_reset(plane);
- plane_state = drm_atomic_helper_plane_duplicate_state(plane); + plane_state = drm_atomic_helper_plane_duplicate_state(plane, + plane->state); } if (!plane_state) return -ENOMEM; diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c index 140c24258b7b..d679fcb9b912 100644 --- a/drivers/gpu/drm/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/drm_dp_mst_topology.c @@ -2995,16 +2995,17 @@ static void drm_dp_destroy_connector_work(struct work_struct *work) }
static struct drm_private_state * -drm_dp_mst_duplicate_state(struct drm_private_obj *obj) +drm_dp_mst_duplicate_state(struct drm_private_obj *obj, + struct drm_private_state *old_state) { struct drm_dp_mst_topology_state *state;
- state = kmemdup(obj->state, sizeof(*state), GFP_KERNEL); + state = kmemdup(old_state, sizeof(*state), GFP_KERNEL); if (!state) return NULL;
__drm_atomic_helper_private_obj_duplicate_state(obj, &state->base, - obj->state); + old_state);
return &state->base; } diff --git a/drivers/gpu/drm/drm_plane_helper.c b/drivers/gpu/drm/drm_plane_helper.c index 06aee1741e96..cf3bbc4a3f6b 100644 --- a/drivers/gpu/drm/drm_plane_helper.c +++ b/drivers/gpu/drm/drm_plane_helper.c @@ -552,12 +552,14 @@ int drm_plane_helper_update(struct drm_plane *plane, struct drm_crtc *crtc, struct drm_plane_state *plane_state;
if (plane->funcs->atomic_duplicate_state) - plane_state = plane->funcs->atomic_duplicate_state(plane); + plane_state = plane->funcs->atomic_duplicate_state(plane, + plane->state); else { if (!plane->state) drm_atomic_helper_plane_reset(plane);
- plane_state = drm_atomic_helper_plane_duplicate_state(plane); + plane_state = drm_atomic_helper_plane_duplicate_state(plane, + plane->state); } if (!plane_state) return -ENOMEM; @@ -601,12 +603,14 @@ int drm_plane_helper_disable(struct drm_plane *plane) return 0;
if (plane->funcs->atomic_duplicate_state) - plane_state = plane->funcs->atomic_duplicate_state(plane); + plane_state = plane->funcs->atomic_duplicate_state(plane, + plane->state); else { if (!plane->state) drm_atomic_helper_plane_reset(plane);
- plane_state = drm_atomic_helper_plane_duplicate_state(plane); + plane_state = drm_atomic_helper_plane_duplicate_state(plane, + plane->state); } if (!plane_state) return -ENOMEM; diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.c b/drivers/gpu/drm/exynos/exynos_drm_plane.c index 1807f4c7bcf6..fc57e880f75c 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_plane.c +++ b/drivers/gpu/drm/exynos/exynos_drm_plane.c @@ -146,18 +146,19 @@ static void exynos_drm_plane_reset(struct drm_plane *plane) }
static struct drm_plane_state * -exynos_drm_plane_duplicate_state(struct drm_plane *plane) +exynos_drm_plane_duplicate_state(struct drm_plane *plane, + struct drm_plane_state *old_state) { struct exynos_drm_plane_state *exynos_state; struct exynos_drm_plane_state *copy;
- exynos_state = to_exynos_plane_state(plane->state); + exynos_state = to_exynos_plane_state(old_state); copy = kzalloc(sizeof(*exynos_state), GFP_KERNEL); if (!copy) return NULL;
__drm_atomic_helper_plane_duplicate_state(plane, ©->base, - plane->state); + old_state); return ©->base; }
diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c index e5d5a558c84a..978902d19c5f 100644 --- a/drivers/gpu/drm/i915/intel_atomic.c +++ b/drivers/gpu/drm/i915/intel_atomic.c @@ -138,16 +138,17 @@ int intel_digital_connector_atomic_check(struct drm_connector *conn, * Returns: The newly allocated connector state, or NULL on failure. */ struct drm_connector_state * -intel_digital_connector_duplicate_state(struct drm_connector *connector) +intel_digital_connector_duplicate_state(struct drm_connector *connector, + struct drm_connector_state *old_state) { struct intel_digital_connector_state *state;
- state = kmemdup(connector->state, sizeof(*state), GFP_KERNEL); + state = kmemdup(old_state, sizeof(*state), GFP_KERNEL); if (!state) return NULL;
__drm_atomic_helper_connector_duplicate_state(connector, &state->base, - connector->state); + old_state); return &state->base; }
@@ -161,16 +162,17 @@ intel_digital_connector_duplicate_state(struct drm_connector *connector) * Returns: The newly allocated crtc state, or NULL on failure. */ struct drm_crtc_state * -intel_crtc_duplicate_state(struct drm_crtc *crtc) +intel_crtc_duplicate_state(struct drm_crtc *crtc, + struct drm_crtc_state *old_state) { struct intel_crtc_state *crtc_state;
- crtc_state = kmemdup(crtc->state, sizeof(*crtc_state), GFP_KERNEL); + crtc_state = kmemdup(old_state, sizeof(*crtc_state), GFP_KERNEL); if (!crtc_state) return NULL;
__drm_atomic_helper_crtc_duplicate_state(crtc, &crtc_state->base, - crtc->state); + old_state);
crtc_state->update_pipe = false; crtc_state->disable_lp_wm = false; diff --git a/drivers/gpu/drm/i915/intel_atomic_plane.c b/drivers/gpu/drm/i915/intel_atomic_plane.c index 41a7354c14d3..4716e8dadba8 100644 --- a/drivers/gpu/drm/i915/intel_atomic_plane.c +++ b/drivers/gpu/drm/i915/intel_atomic_plane.c @@ -71,19 +71,20 @@ intel_create_plane_state(struct drm_plane *plane) * Returns: The newly allocated plane state, or NULL on failure. */ struct drm_plane_state * -intel_plane_duplicate_state(struct drm_plane *plane) +intel_plane_duplicate_state(struct drm_plane *plane, + struct drm_plane_state *old_state) { struct drm_plane_state *state; struct intel_plane_state *intel_state;
- intel_state = kmemdup(plane->state, sizeof(*intel_state), GFP_KERNEL); + intel_state = kmemdup(old_state, sizeof(*intel_state), GFP_KERNEL);
if (!intel_state) return NULL;
state = &intel_state->base;
- __drm_atomic_helper_plane_duplicate_state(plane, state, plane->state); + __drm_atomic_helper_plane_duplicate_state(plane, state, old_state);
intel_state->vma = NULL;
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 791204c8621c..1016afebef27 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -13646,7 +13646,7 @@ intel_legacy_cursor_update(struct drm_plane *plane, !old_plane_state->fb != !fb) goto slow;
- new_plane_state = intel_plane_duplicate_state(plane); + new_plane_state = intel_plane_duplicate_state(plane, plane->state); if (!new_plane_state) return -ENOMEM;
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index ea36d1a61e86..4be10983e7cc 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1945,9 +1945,11 @@ int intel_digital_connector_atomic_set_property(struct drm_connector *connector, int intel_digital_connector_atomic_check(struct drm_connector *conn, struct drm_connector_state *new_state); struct drm_connector_state * -intel_digital_connector_duplicate_state(struct drm_connector *connector); +intel_digital_connector_duplicate_state(struct drm_connector *connector, + struct drm_connector_state *old_state);
-struct drm_crtc_state *intel_crtc_duplicate_state(struct drm_crtc *crtc); +struct drm_crtc_state *intel_crtc_duplicate_state(struct drm_crtc *crtc, + struct drm_crtc_state *old_state); void intel_crtc_destroy_state(struct drm_crtc *crtc, struct drm_crtc_state *state); struct drm_atomic_state *intel_atomic_state_alloc(struct drm_device *dev); @@ -1996,7 +1998,8 @@ int intel_atomic_setup_scalers(struct drm_i915_private *dev_priv,
/* intel_atomic_plane.c */ struct intel_plane_state *intel_create_plane_state(struct drm_plane *plane); -struct drm_plane_state *intel_plane_duplicate_state(struct drm_plane *plane); +struct drm_plane_state *intel_plane_duplicate_state(struct drm_plane *plane, + struct drm_plane_state *old_state); void intel_plane_destroy_state(struct drm_plane *plane, struct drm_plane_state *state); extern const struct drm_plane_helper_funcs intel_plane_helper_funcs; diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 0d14807b38a5..9ed722b1c6fd 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -2179,17 +2179,18 @@ intel_sdvo_connector_unregister(struct drm_connector *connector) }
static struct drm_connector_state * -intel_sdvo_connector_duplicate_state(struct drm_connector *connector) +intel_sdvo_connector_duplicate_state(struct drm_connector *connector, + struct drm_connector_state *old_state) { struct intel_sdvo_connector_state *state;
- state = kmemdup(connector->state, sizeof(*state), GFP_KERNEL); + state = kmemdup(old_state, sizeof(*state), GFP_KERNEL); if (!state) return NULL;
__drm_atomic_helper_connector_duplicate_state(connector, &state->base.base, - connector->state); + old_state); return &state->base.base; }
diff --git a/drivers/gpu/drm/imx/ipuv3-crtc.c b/drivers/gpu/drm/imx/ipuv3-crtc.c index 44598b6a5cfc..666c02f27a3c 100644 --- a/drivers/gpu/drm/imx/ipuv3-crtc.c +++ b/drivers/gpu/drm/imx/ipuv3-crtc.c @@ -129,7 +129,8 @@ static void imx_drm_crtc_reset(struct drm_crtc *crtc) state->base.crtc = crtc; }
-static struct drm_crtc_state *imx_drm_crtc_duplicate_state(struct drm_crtc *crtc) +static struct drm_crtc_state *imx_drm_crtc_duplicate_state(struct drm_crtc *crtc, + struct drm_crtc_state *old_state) { struct imx_crtc_state *state;
@@ -138,7 +139,7 @@ static struct drm_crtc_state *imx_drm_crtc_duplicate_state(struct drm_crtc *crtc return NULL;
__drm_atomic_helper_crtc_duplicate_state(crtc, &state->base, - crtc->state); + old_state);
WARN_ON(state->base.crtc != crtc); state->base.crtc = crtc; diff --git a/drivers/gpu/drm/imx/ipuv3-plane.c b/drivers/gpu/drm/imx/ipuv3-plane.c index 3b3c979c4f6d..474fff30ae79 100644 --- a/drivers/gpu/drm/imx/ipuv3-plane.c +++ b/drivers/gpu/drm/imx/ipuv3-plane.c @@ -279,17 +279,18 @@ void ipu_plane_state_reset(struct drm_plane *plane) plane->state = &ipu_state->base; }
-struct drm_plane_state *ipu_plane_duplicate_state(struct drm_plane *plane) +struct drm_plane_state *ipu_plane_duplicate_state(struct drm_plane *plane, + struct drm_plane_state *old_state) { struct ipu_plane_state *state;
- if (WARN_ON(!plane->state)) + if (WARN_ON(!old_state)) return NULL;
state = kmalloc(sizeof(*state), GFP_KERNEL); if (state) __drm_atomic_helper_plane_duplicate_state(plane, &state->base, - plane->state); + old_state);
return &state->base; } diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c index 4bdc612fbe89..c11d0f26a4b5 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c @@ -126,7 +126,8 @@ static void mtk_drm_crtc_reset(struct drm_crtc *crtc) state->base.crtc = crtc; }
-static struct drm_crtc_state *mtk_drm_crtc_duplicate_state(struct drm_crtc *crtc) +static struct drm_crtc_state *mtk_drm_crtc_duplicate_state(struct drm_crtc *crtc, + struct drm_crtc_state *old_state) { struct mtk_crtc_state *state;
@@ -135,7 +136,7 @@ static struct drm_crtc_state *mtk_drm_crtc_duplicate_state(struct drm_crtc *crtc return NULL;
__drm_atomic_helper_crtc_duplicate_state(crtc, &state->base, - crtc->state); + old_state);
WARN_ON(state->base.crtc != crtc); state->base.crtc = crtc; diff --git a/drivers/gpu/drm/mediatek/mtk_drm_plane.c b/drivers/gpu/drm/mediatek/mtk_drm_plane.c index 67c7bd17e350..a0ccad4c577e 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_plane.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_plane.c @@ -50,9 +50,10 @@ static void mtk_plane_reset(struct drm_plane *plane) state->pending.format = DRM_FORMAT_RGB565; }
-static struct drm_plane_state *mtk_plane_duplicate_state(struct drm_plane *plane) +static struct drm_plane_state *mtk_plane_duplicate_state(struct drm_plane *plane, + struct drm_plane_state *old_state) { - struct mtk_plane_state *old_mtk_state = to_mtk_plane_state(plane->state); + struct mtk_plane_state *old_mtk_state = to_mtk_plane_state(old_state); struct mtk_plane_state *state;
state = kzalloc(sizeof(*state), GFP_KERNEL); @@ -60,7 +61,7 @@ static struct drm_plane_state *mtk_plane_duplicate_state(struct drm_plane *plane return NULL;
__drm_atomic_helper_plane_duplicate_state(plane, &state->base, - plane->state); + old_state);
WARN_ON(state->base.plane != plane);
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c index 49c7410d0ef6..2f0d08dc15b1 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c @@ -889,20 +889,21 @@ static void mdp5_crtc_reset(struct drm_crtc *crtc) }
static struct drm_crtc_state * -mdp5_crtc_duplicate_state(struct drm_crtc *crtc) +mdp5_crtc_duplicate_state(struct drm_crtc *crtc, + struct drm_crtc_state *old_state) { struct mdp5_crtc_state *mdp5_cstate;
- if (WARN_ON(!crtc->state)) + if (WARN_ON(!old_state)) return NULL;
- mdp5_cstate = kmemdup(to_mdp5_crtc_state(crtc->state), + mdp5_cstate = kmemdup(to_mdp5_crtc_state(old_state), sizeof(*mdp5_cstate), GFP_KERNEL); if (!mdp5_cstate) return NULL;
__drm_atomic_helper_crtc_duplicate_state(crtc, &mdp5_cstate->base, - crtc->state); + old_state);
return &mdp5_cstate->base; } diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c index de00c9ad14fd..7400632877ff 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c @@ -214,20 +214,21 @@ static void mdp5_plane_reset(struct drm_plane *plane) }
static struct drm_plane_state * -mdp5_plane_duplicate_state(struct drm_plane *plane) +mdp5_plane_duplicate_state(struct drm_plane *plane, + struct drm_plane_state *old_state) { struct mdp5_plane_state *mdp5_state;
- if (WARN_ON(!plane->state)) + if (WARN_ON(!old_state)) return NULL;
- mdp5_state = kmemdup(to_mdp5_plane_state(plane->state), - sizeof(*mdp5_state), GFP_KERNEL); + mdp5_state = kmemdup(to_mdp5_plane_state(old_state), + sizeof(*mdp5_state), GFP_KERNEL); if (!mdp5_state) return NULL;
__drm_atomic_helper_plane_duplicate_state(plane, &mdp5_state->base, - plane->state); + old_state);
return &mdp5_state->base; } @@ -1032,7 +1033,7 @@ static int mdp5_update_cursor_plane_legacy(struct drm_plane *plane, plane_state->fb != fb) goto slow;
- new_plane_state = mdp5_plane_duplicate_state(plane); + new_plane_state = mdp5_plane_duplicate_state(plane, plane->state); if (!new_plane_state) return -ENOMEM;
diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index dc1880eb00bf..4418220e3d6c 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -228,14 +228,15 @@ nouveau_conn_atomic_destroy_state(struct drm_connector *connector, }
struct drm_connector_state * -nouveau_conn_atomic_duplicate_state(struct drm_connector *connector) +nouveau_conn_atomic_duplicate_state(struct drm_connector *connector, + struct drm_connector_state *old_state) { - struct nouveau_conn_atom *armc = nouveau_conn_atom(connector->state); + struct nouveau_conn_atom *armc = nouveau_conn_atom(old_state); struct nouveau_conn_atom *asyc; if (!(asyc = kmalloc(sizeof(*asyc), GFP_KERNEL))) return NULL; __drm_atomic_helper_connector_duplicate_state(connector, &asyc->state, - connector->state); + old_state); asyc->dither = armc->dither; asyc->scaler = armc->scaler; asyc->procamp = armc->procamp; diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.h b/drivers/gpu/drm/nouveau/nouveau_connector.h index a4d1a059bd3d..2e4b20f5ffb7 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.h +++ b/drivers/gpu/drm/nouveau/nouveau_connector.h @@ -141,7 +141,8 @@ struct nouveau_conn_atom { void nouveau_conn_attach_properties(struct drm_connector *); void nouveau_conn_reset(struct drm_connector *); struct drm_connector_state * -nouveau_conn_atomic_duplicate_state(struct drm_connector *); +nouveau_conn_atomic_duplicate_state(struct drm_connector *, + struct drm_connector_state *); void nouveau_conn_atomic_destroy_state(struct drm_connector *, struct drm_connector_state *); int nouveau_conn_atomic_set_property(struct drm_connector *, diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index 6ca8d97e7dbc..a2401c3894a1 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -1005,14 +1005,15 @@ nv50_wndw_atomic_destroy_state(struct drm_plane *plane, }
static struct drm_plane_state * -nv50_wndw_atomic_duplicate_state(struct drm_plane *plane) +nv50_wndw_atomic_duplicate_state(struct drm_plane *plane, + struct drm_plane_state *old_state) { - struct nv50_wndw_atom *armw = nv50_wndw_atom(plane->state); + struct nv50_wndw_atom *armw = nv50_wndw_atom(old_state); struct nv50_wndw_atom *asyw; if (!(asyw = kmalloc(sizeof(*asyw), GFP_KERNEL))) return NULL; __drm_atomic_helper_plane_duplicate_state(plane, &asyw->state, - plane->state); + old_state); asyw->interval = 1; asyw->sema = armw->sema; asyw->ntfy = armw->ntfy; @@ -2258,14 +2259,15 @@ nv50_head_atomic_destroy_state(struct drm_crtc *crtc, }
static struct drm_crtc_state * -nv50_head_atomic_duplicate_state(struct drm_crtc *crtc) +nv50_head_atomic_duplicate_state(struct drm_crtc *crtc, + struct drm_crtc_state *old_state) { - struct nv50_head_atom *armh = nv50_head_atom(crtc->state); + struct nv50_head_atom *armh = nv50_head_atom(old_state); struct nv50_head_atom *asyh; if (!(asyh = kmalloc(sizeof(*asyh), GFP_KERNEL))) return NULL; __drm_atomic_helper_crtc_duplicate_state(crtc, &asyh->state, - crtc->state); + old_state); asyh->view = armh->view; asyh->mode = armh->mode; asyh->lut = armh->lut; diff --git a/drivers/gpu/drm/rcar-du/rcar_du_plane.c b/drivers/gpu/drm/rcar-du/rcar_du_plane.c index a856507f5717..a46a5eee89ef 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_plane.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_plane.c @@ -610,21 +610,22 @@ static const struct drm_plane_helper_funcs rcar_du_plane_helper_funcs = { };
static struct drm_plane_state * -rcar_du_plane_atomic_duplicate_state(struct drm_plane *plane) +rcar_du_plane_atomic_duplicate_state(struct drm_plane *plane, + struct drm_plane_state *old_state) { struct rcar_du_plane_state *state; struct rcar_du_plane_state *copy;
- if (WARN_ON(!plane->state)) + if (WARN_ON(!old_state)) return NULL;
- state = to_rcar_plane_state(plane->state); + state = to_rcar_plane_state(old_state); copy = kmemdup(state, sizeof(*state), GFP_KERNEL); if (copy == NULL) return NULL;
__drm_atomic_helper_plane_duplicate_state(plane, ©->state, - plane->state); + old_state);
return ©->state; } diff --git a/drivers/gpu/drm/rcar-du/rcar_du_vsp.c b/drivers/gpu/drm/rcar-du/rcar_du_vsp.c index 21a30775edb7..5f1547f4215e 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_vsp.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_vsp.c @@ -303,21 +303,22 @@ static const struct drm_plane_helper_funcs rcar_du_vsp_plane_helper_funcs = { };
static struct drm_plane_state * -rcar_du_vsp_plane_atomic_duplicate_state(struct drm_plane *plane) +rcar_du_vsp_plane_atomic_duplicate_state(struct drm_plane *plane, + struct drm_plane_state *old_state) { struct rcar_du_vsp_plane_state *state; struct rcar_du_vsp_plane_state *copy;
- if (WARN_ON(!plane->state)) + if (WARN_ON(!old_state)) return NULL;
- state = to_rcar_vsp_plane_state(plane->state); + state = to_rcar_vsp_plane_state(old_state); copy = kmemdup(state, sizeof(*state), GFP_KERNEL); if (copy == NULL) return NULL;
__drm_atomic_helper_plane_duplicate_state(plane, ©->state, - plane->state); + old_state);
return ©->state; } diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index 9f586f698e52..a8af4d752b68 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -1104,7 +1104,8 @@ static void vop_crtc_reset(struct drm_crtc *crtc) crtc->state->crtc = crtc; }
-static struct drm_crtc_state *vop_crtc_duplicate_state(struct drm_crtc *crtc) +static struct drm_crtc_state *vop_crtc_duplicate_state(struct drm_crtc *crtc, + struct drm_crtc_state *old_state) { struct rockchip_crtc_state *rockchip_state;
@@ -1113,7 +1114,7 @@ static struct drm_crtc_state *vop_crtc_duplicate_state(struct drm_crtc *crtc) return NULL;
__drm_atomic_helper_crtc_duplicate_state(crtc, &rockchip_state->base, - crtc->state); + old_state); return &rockchip_state->base; }
diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c index d725115d011d..5e3d02ae9653 100644 --- a/drivers/gpu/drm/tegra/dc.c +++ b/drivers/gpu/drm/tegra/dc.c @@ -448,9 +448,10 @@ static void tegra_plane_reset(struct drm_plane *plane) } }
-static struct drm_plane_state *tegra_plane_atomic_duplicate_state(struct drm_plane *plane) +static struct drm_plane_state *tegra_plane_atomic_duplicate_state(struct drm_plane *plane, + struct drm_plane_state *old_state) { - struct tegra_plane_state *state = to_tegra_plane_state(plane->state); + struct tegra_plane_state *state = to_tegra_plane_state(old_state); struct tegra_plane_state *copy;
copy = kmalloc(sizeof(*copy), GFP_KERNEL); @@ -458,7 +459,7 @@ static struct drm_plane_state *tegra_plane_atomic_duplicate_state(struct drm_pla return NULL;
__drm_atomic_helper_plane_duplicate_state(plane, ©->base, - plane->state); + old_state); copy->tiling = state->tiling; copy->format = state->format; copy->swap = state->swap; @@ -1034,9 +1035,10 @@ static void tegra_crtc_reset(struct drm_crtc *crtc) }
static struct drm_crtc_state * -tegra_crtc_atomic_duplicate_state(struct drm_crtc *crtc) +tegra_crtc_atomic_duplicate_state(struct drm_crtc *crtc, + struct drm_crtc_state *old_state) { - struct tegra_dc_state *state = to_dc_state(crtc->state); + struct tegra_dc_state *state = to_dc_state(old_state); struct tegra_dc_state *copy;
copy = kmalloc(sizeof(*copy), GFP_KERNEL); @@ -1044,7 +1046,7 @@ tegra_crtc_atomic_duplicate_state(struct drm_crtc *crtc) return NULL;
__drm_atomic_helper_crtc_duplicate_state(crtc, ©->base, - crtc->state); + old_state); copy->clk = state->clk; copy->pclk = state->pclk; copy->div = state->div; diff --git a/drivers/gpu/drm/tegra/dsi.c b/drivers/gpu/drm/tegra/dsi.c index ce646493e939..9156434e0627 100644 --- a/drivers/gpu/drm/tegra/dsi.c +++ b/drivers/gpu/drm/tegra/dsi.c @@ -799,9 +799,10 @@ static void tegra_dsi_connector_reset(struct drm_connector *connector) }
static struct drm_connector_state * -tegra_dsi_connector_duplicate_state(struct drm_connector *connector) +tegra_dsi_connector_duplicate_state(struct drm_connector *connector, + struct drm_connector_state *old_state) { - struct tegra_dsi_state *state = to_dsi_state(connector->state); + struct tegra_dsi_state *state = to_dsi_state(old_state); struct tegra_dsi_state *copy;
copy = kmemdup(state, sizeof(*state), GFP_KERNEL); @@ -810,7 +811,7 @@ tegra_dsi_connector_duplicate_state(struct drm_connector *connector)
__drm_atomic_helper_connector_duplicate_state(connector, ©->base, - connector->state); + old_state);
return ©->base; } diff --git a/drivers/gpu/drm/tegra/sor.c b/drivers/gpu/drm/tegra/sor.c index 02c3439c2e96..4e79ae0561cd 100644 --- a/drivers/gpu/drm/tegra/sor.c +++ b/drivers/gpu/drm/tegra/sor.c @@ -1325,9 +1325,10 @@ tegra_sor_connector_detect(struct drm_connector *connector, bool force) }
static struct drm_connector_state * -tegra_sor_connector_duplicate_state(struct drm_connector *connector) +tegra_sor_connector_duplicate_state(struct drm_connector *connector, + struct drm_connector_state *old_state) { - struct tegra_sor_state *state = to_sor_state(connector->state); + struct tegra_sor_state *state = to_sor_state(old_state); struct tegra_sor_state *copy;
copy = kmemdup(state, sizeof(*state), GFP_KERNEL); @@ -1335,7 +1336,7 @@ tegra_sor_connector_duplicate_state(struct drm_connector *connector) return NULL;
__drm_atomic_helper_connector_duplicate_state(connector, ©->base, - connector->state); + old_state);
return ©->base; } diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c index 28bdfb5adb9e..1d7e46af7450 100644 --- a/drivers/gpu/drm/vc4/vc4_crtc.c +++ b/drivers/gpu/drm/vc4/vc4_crtc.c @@ -813,7 +813,8 @@ static int vc4_page_flip(struct drm_crtc *crtc, return drm_atomic_helper_page_flip(crtc, fb, event, flags, ctx); }
-static struct drm_crtc_state *vc4_crtc_duplicate_state(struct drm_crtc *crtc) +static struct drm_crtc_state *vc4_crtc_duplicate_state(struct drm_crtc *crtc, + struct drm_crtc_state *old_state) { struct vc4_crtc_state *vc4_state;
@@ -822,7 +823,7 @@ static struct drm_crtc_state *vc4_crtc_duplicate_state(struct drm_crtc *crtc) return NULL;
__drm_atomic_helper_crtc_duplicate_state(crtc, &vc4_state->base, - crtc->state); + old_state); return &vc4_state->base; }
diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c index 43b388a42c1e..0c57309d6c2f 100644 --- a/drivers/gpu/drm/vc4/vc4_plane.c +++ b/drivers/gpu/drm/vc4/vc4_plane.c @@ -174,21 +174,22 @@ static bool plane_enabled(struct drm_plane_state *state) return state->fb && state->crtc; }
-static struct drm_plane_state *vc4_plane_duplicate_state(struct drm_plane *plane) +static struct drm_plane_state *vc4_plane_duplicate_state(struct drm_plane *plane, + struct drm_plane_state *old_state) { struct vc4_plane_state *vc4_state;
- if (WARN_ON(!plane->state)) + if (WARN_ON(!old_state)) return NULL;
- vc4_state = kmemdup(plane->state, sizeof(*vc4_state), GFP_KERNEL); + vc4_state = kmemdup(old_state, sizeof(*vc4_state), GFP_KERNEL); if (!vc4_state) return NULL;
memset(&vc4_state->lbm, 0, sizeof(vc4_state->lbm));
__drm_atomic_helper_plane_duplicate_state(plane, &vc4_state->base, - plane->state); + old_state);
if (vc4_state->dlist) { vc4_state->dlist = kmemdup(vc4_state->dlist, diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index dc3b4a9e3d25..946f11c93619 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -597,22 +597,23 @@ void vmw_du_crtc_atomic_flush(struct drm_crtc *crtc, * Returns: The newly allocated crtc state, or NULL on failure. */ struct drm_crtc_state * -vmw_du_crtc_duplicate_state(struct drm_crtc *crtc) +vmw_du_crtc_duplicate_state(struct drm_crtc *crtc, + struct drm_crtc_state *old_state) { struct drm_crtc_state *state; struct vmw_crtc_state *vcs;
- if (WARN_ON(!crtc->state)) + if (WARN_ON(!old_state)) return NULL;
- vcs = kmemdup(crtc->state, sizeof(*vcs), GFP_KERNEL); + vcs = kmemdup(old_state, sizeof(*vcs), GFP_KERNEL);
if (!vcs) return NULL;
state = &vcs->base;
- __drm_atomic_helper_crtc_duplicate_state(crtc, state, crtc->state); + __drm_atomic_helper_crtc_duplicate_state(crtc, state, old_state);
return state; } @@ -675,12 +676,13 @@ vmw_du_crtc_destroy_state(struct drm_crtc *crtc, * Returns: The newly allocated plane state, or NULL on failure. */ struct drm_plane_state * -vmw_du_plane_duplicate_state(struct drm_plane *plane) +vmw_du_plane_duplicate_state(struct drm_plane *plane, + struct drm_plane_state *old_state) { struct drm_plane_state *state; struct vmw_plane_state *vps;
- vps = kmemdup(plane->state, sizeof(*vps), GFP_KERNEL); + vps = kmemdup(old_state, sizeof(*vps), GFP_KERNEL);
if (!vps) return NULL; @@ -701,7 +703,7 @@ vmw_du_plane_duplicate_state(struct drm_plane *plane)
state = &vps->base;
- __drm_atomic_helper_plane_duplicate_state(plane, state, plane->state); + __drm_atomic_helper_plane_duplicate_state(plane, state, old_state);
return state; } @@ -781,15 +783,16 @@ vmw_du_plane_destroy_state(struct drm_plane *plane, * Returns: The newly allocated connector state, or NULL on failure. */ struct drm_connector_state * -vmw_du_connector_duplicate_state(struct drm_connector *connector) +vmw_du_connector_duplicate_state(struct drm_connector *connector, + struct drm_connector_state *old_state) { struct drm_connector_state *state; struct vmw_connector_state *vcs;
- if (WARN_ON(!connector->state)) + if (WARN_ON(!old_state)) return NULL;
- vcs = kmemdup(connector->state, sizeof(*vcs), GFP_KERNEL); + vcs = kmemdup(old_state, sizeof(*vcs), GFP_KERNEL);
if (!vcs) return NULL; @@ -797,7 +800,7 @@ vmw_du_connector_duplicate_state(struct drm_connector *connector) state = &vcs->base;
__drm_atomic_helper_connector_duplicate_state(connector, state, - connector->state); + old_state);
return state; } diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h index ff9c8389ff21..4769c8a412c2 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h @@ -348,7 +348,8 @@ int vmw_du_cursor_plane_prepare_fb(struct drm_plane *plane, void vmw_du_plane_cleanup_fb(struct drm_plane *plane, struct drm_plane_state *old_state); void vmw_du_plane_reset(struct drm_plane *plane); -struct drm_plane_state *vmw_du_plane_duplicate_state(struct drm_plane *plane); +struct drm_plane_state *vmw_du_plane_duplicate_state(struct drm_plane *plane, + struct drm_plane_state *old_state); void vmw_du_plane_destroy_state(struct drm_plane *plane, struct drm_plane_state *state); void vmw_du_plane_unpin_surf(struct vmw_plane_state *vps, @@ -361,12 +362,14 @@ void vmw_du_crtc_atomic_begin(struct drm_crtc *crtc, void vmw_du_crtc_atomic_flush(struct drm_crtc *crtc, struct drm_crtc_state *old_crtc_state); void vmw_du_crtc_reset(struct drm_crtc *crtc); -struct drm_crtc_state *vmw_du_crtc_duplicate_state(struct drm_crtc *crtc); +struct drm_crtc_state *vmw_du_crtc_duplicate_state(struct drm_crtc *crtc, + struct drm_crtc_state *old_state); void vmw_du_crtc_destroy_state(struct drm_crtc *crtc, struct drm_crtc_state *state); void vmw_du_connector_reset(struct drm_connector *connector); struct drm_connector_state * -vmw_du_connector_duplicate_state(struct drm_connector *connector); +vmw_du_connector_duplicate_state(struct drm_connector *connector, + struct drm_connector_state *old_state);
void vmw_du_connector_destroy_state(struct drm_connector *connector, struct drm_connector_state *state); diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h index addec49a14bf..0e6c54b3e0af 100644 --- a/include/drm/drm_atomic.h +++ b/include/drm/drm_atomic.h @@ -180,7 +180,8 @@ struct drm_private_state_funcs { * Duplicated atomic state or NULL when obj->state is not * initialized or allocation failed. */ - struct drm_private_state *(*atomic_duplicate_state)(struct drm_private_obj *obj); + struct drm_private_state *(*atomic_duplicate_state)(struct drm_private_obj *obj, + struct drm_private_state *old_state);
/** * @atomic_destroy_state: diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h index 0adacaca0941..b799687a4b09 100644 --- a/include/drm/drm_atomic_helper.h +++ b/include/drm/drm_atomic_helper.h @@ -155,7 +155,8 @@ void __drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc, struct drm_crtc_state *state, const struct drm_crtc_state *old_state); struct drm_crtc_state * -drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc); +drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc, + struct drm_crtc_state *old_state); void __drm_atomic_helper_crtc_destroy_state(struct drm_crtc_state *state); void drm_atomic_helper_crtc_destroy_state(struct drm_crtc *crtc, struct drm_crtc_state *state); @@ -165,7 +166,8 @@ void __drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane, struct drm_plane_state *state, const struct drm_plane_state *old_state); struct drm_plane_state * -drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane); +drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane, + struct drm_plane_state *old_state); void __drm_atomic_helper_plane_destroy_state(struct drm_plane_state *state); void drm_atomic_helper_plane_destroy_state(struct drm_plane *plane, struct drm_plane_state *state); @@ -178,7 +180,8 @@ __drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector, struct drm_connector_state *state, const struct drm_connector_state *old_state); struct drm_connector_state * -drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector); +drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector, + struct drm_connector_state *old_state); struct drm_atomic_state * drm_atomic_helper_duplicate_state(struct drm_device *dev, struct drm_modeset_acquire_ctx *ctx); diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index ae5b7dc316c8..ee9a15a87db5 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -540,7 +540,8 @@ struct drm_connector_funcs { * * Duplicated atomic state or NULL when the allocation failed. */ - struct drm_connector_state *(*atomic_duplicate_state)(struct drm_connector *connector); + struct drm_connector_state *(*atomic_duplicate_state)(struct drm_connector *connector, + struct drm_connector_state *old_state);
/** * @atomic_destroy_state: diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 3a911a64c257..1d187331fe5d 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -523,7 +523,8 @@ struct drm_crtc_funcs { * * Duplicated atomic state or NULL when the allocation failed. */ - struct drm_crtc_state *(*atomic_duplicate_state)(struct drm_crtc *crtc); + struct drm_crtc_state *(*atomic_duplicate_state)(struct drm_crtc *crtc, + struct drm_crtc_state *old_state);
/** * @atomic_destroy_state: diff --git a/include/drm/drm_plane.h b/include/drm/drm_plane.h index 9ab3e7044812..f01023ed1c7b 100644 --- a/include/drm/drm_plane.h +++ b/include/drm/drm_plane.h @@ -275,7 +275,8 @@ struct drm_plane_funcs { * * Duplicated atomic state or NULL when the allocation failed. */ - struct drm_plane_state *(*atomic_duplicate_state)(struct drm_plane *plane); + struct drm_plane_state *(*atomic_duplicate_state)(struct drm_plane *plane, + struct drm_plane_state *old_state);
/** * @atomic_destroy_state:
From: Ville Syrjälä ville.syrjala@linux.intel.com
Coccinelle doesn't fix up the docs for us, so let's do it manually.
Signed-off-by: Ville Syrjälä ville.syrjala@linux.intel.com --- drivers/gpu/drm/drm_atomic_helper.c | 12 +++++++++--- include/drm/drm_connector.h | 2 +- include/drm/drm_crtc.h | 2 +- include/drm/drm_plane.h | 2 +- 4 files changed, 12 insertions(+), 6 deletions(-)
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index c60fb6289276..f0887f231fb8 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -3368,7 +3368,8 @@ EXPORT_SYMBOL(drm_atomic_helper_crtc_reset); /** * __drm_atomic_helper_crtc_duplicate_state - copy atomic CRTC state * @crtc: CRTC object - * @state: atomic CRTC state + * @state: new CRTC state + * @old_state: old CRTC state * * Copies atomic state from a CRTC's current state and resets inferred values. * This is useful for drivers that subclass the CRTC state. @@ -3401,6 +3402,7 @@ EXPORT_SYMBOL(__drm_atomic_helper_crtc_duplicate_state); /** * drm_atomic_helper_crtc_duplicate_state - default state duplicate hook * @crtc: drm CRTC + * @old_state: old CRTC state * * Default CRTC state duplicate hook for drivers which don't have their own * subclassed CRTC state structure. @@ -3481,7 +3483,8 @@ EXPORT_SYMBOL(drm_atomic_helper_plane_reset); /** * __drm_atomic_helper_plane_duplicate_state - copy atomic plane state * @plane: plane object - * @state: atomic plane state + * @state: new plane state + * @old_state: old plane state * * Copies atomic state from a plane's current state. This is useful for * drivers that subclass the plane state. @@ -3502,6 +3505,7 @@ EXPORT_SYMBOL(__drm_atomic_helper_plane_duplicate_state); /** * drm_atomic_helper_plane_duplicate_state - default state duplicate hook * @plane: drm plane + * @old_state: old plane state * * Default plane state duplicate hook for drivers which don't have their own * subclassed plane state structure. @@ -3605,7 +3609,8 @@ EXPORT_SYMBOL(drm_atomic_helper_connector_reset); /** * __drm_atomic_helper_connector_duplicate_state - copy atomic connector state * @connector: connector object - * @state: atomic connector state + * @state: new connector state + * @old_state: old connector state * * Copies atomic state from a connector's current state. This is useful for * drivers that subclass the connector state. @@ -3624,6 +3629,7 @@ EXPORT_SYMBOL(__drm_atomic_helper_connector_duplicate_state); /** * drm_atomic_helper_connector_duplicate_state - default state duplicate hook * @connector: drm connector + * @old_state: old connector state * * Default connector state duplicate hook for drivers which don't have their own * subclassed connector state structure. diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index ee9a15a87db5..a0d862d23082 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -514,7 +514,7 @@ struct drm_connector_funcs { /** * @atomic_duplicate_state: * - * Duplicate the current atomic state for this connector and return it. + * Duplicate the passed in atomic state for this connector and return it. * The core and helpers guarantee that any atomic state duplicated with * this hook and still owned by the caller (i.e. not transferred to the * driver by calling &drm_mode_config_funcs.atomic_commit) will be diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 1d187331fe5d..8bfbc54660ab 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -497,7 +497,7 @@ struct drm_crtc_funcs { /** * @atomic_duplicate_state: * - * Duplicate the current atomic state for this CRTC and return it. + * Duplicate the passed in atomic state for this CRTC and return it. * The core and helpers guarantee that any atomic state duplicated with * this hook and still owned by the caller (i.e. not transferred to the * driver by calling &drm_mode_config_funcs.atomic_commit) will be diff --git a/include/drm/drm_plane.h b/include/drm/drm_plane.h index f01023ed1c7b..08ad4b58adbe 100644 --- a/include/drm/drm_plane.h +++ b/include/drm/drm_plane.h @@ -249,7 +249,7 @@ struct drm_plane_funcs { /** * @atomic_duplicate_state: * - * Duplicate the current atomic state for this plane and return it. + * Duplicate the passed in atomic state for this plane and return it. * The core and helpers guarantee that any atomic state duplicated with * this hook and still owned by the caller (i.e. not transferred to the * driver by calling &drm_mode_config_funcs.atomic_commit) will be
From: Ville Syrjälä ville.syrjala@linux.intel.com
Make drm_connector_get() return the connector. This allows the nice pattern of 'foo->connector = drm_connector_get(connector)'
Signed-off-by: Ville Syrjälä ville.syrjala@linux.intel.com --- drivers/gpu/drm/drm_atomic.c | 3 +-- drivers/gpu/drm/drm_fb_helper.c | 7 +++---- include/drm/drm_connector.h | 7 ++++++- 3 files changed, 10 insertions(+), 7 deletions(-)
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index b1983e7b65d2..56925b93f598 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -1139,11 +1139,10 @@ drm_atomic_get_connector_state(struct drm_atomic_state *state, if (!connector_state) return ERR_PTR(-ENOMEM);
- drm_connector_get(connector); c->state = connector_state; c->old_state = connector->state; c->new_state = connector_state; - c->ptr = connector; + c->ptr = drm_connector_get(connector); connector_state->state = state;
state->num_connector = state->connectors.num_elems; diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 721511da4de6..f520c235a6fb 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -138,8 +138,7 @@ static int __drm_fb_helper_add_one_connector(struct drm_fb_helper *fb_helper, if (!fb_conn) return -ENOMEM;
- drm_connector_get(connector); - fb_conn->connector = connector; + fb_conn->connector = drm_connector_get(connector); fb_helper->connector_info[fb_helper->connector_count++] = fb_conn;
return 0; @@ -2338,8 +2337,8 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper, fb_crtc->y = offset->y; modeset->mode = drm_mode_duplicate(dev, fb_crtc->desired_mode); - drm_connector_get(connector); - modeset->connectors[modeset->num_connectors++] = connector; + modeset->connectors[modeset->num_connectors++] = + drm_connector_get(connector); modeset->fb = fb_helper->fb; modeset->x = offset->x; modeset->y = offset->y; diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index a0d862d23082..8f26166f78b4 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -916,10 +916,15 @@ static inline struct drm_connector *drm_connector_lookup(struct drm_device *dev, * @connector: DRM connector * * This function increments the connector's refcount. + + * Returns: + * + * The connector. */ -static inline void drm_connector_get(struct drm_connector *connector) +static inline struct drm_connector *drm_connector_get(struct drm_connector *connector) { drm_mode_object_get(&connector->base); + return connector; }
/**
Op 06-07-17 om 22:24 schreef ville.syrjala@linux.intel.com:
From: Ville Syrjälä ville.syrjala@linux.intel.com
Make drm_connector_get() return the connector. This allows the nice pattern of 'foo->connector = drm_connector_get(connector)'
Signed-off-by: Ville Syrjälä ville.syrjala@linux.intel.com
Reviewed-by: Maarten Lankhorst maarten.lankhorst@linux.intel.com
drivers/gpu/drm/drm_atomic.c | 3 +-- drivers/gpu/drm/drm_fb_helper.c | 7 +++---- include/drm/drm_connector.h | 7 ++++++- 3 files changed, 10 insertions(+), 7 deletions(-)
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index b1983e7b65d2..56925b93f598 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -1139,11 +1139,10 @@ drm_atomic_get_connector_state(struct drm_atomic_state *state, if (!connector_state) return ERR_PTR(-ENOMEM);
- drm_connector_get(connector); c->state = connector_state; c->old_state = connector->state; c->new_state = connector_state;
- c->ptr = connector;
c->ptr = drm_connector_get(connector); connector_state->state = state;
state->num_connector = state->connectors.num_elems;
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 721511da4de6..f520c235a6fb 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -138,8 +138,7 @@ static int __drm_fb_helper_add_one_connector(struct drm_fb_helper *fb_helper, if (!fb_conn) return -ENOMEM;
- drm_connector_get(connector);
- fb_conn->connector = connector;
fb_conn->connector = drm_connector_get(connector); fb_helper->connector_info[fb_helper->connector_count++] = fb_conn;
return 0;
@@ -2338,8 +2337,8 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper, fb_crtc->y = offset->y; modeset->mode = drm_mode_duplicate(dev, fb_crtc->desired_mode);
drm_connector_get(connector);
modeset->connectors[modeset->num_connectors++] = connector;
modeset->connectors[modeset->num_connectors++] =
drm_connector_get(connector); modeset->fb = fb_helper->fb; modeset->x = offset->x; modeset->y = offset->y;
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index a0d862d23082..8f26166f78b4 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -916,10 +916,15 @@ static inline struct drm_connector *drm_connector_lookup(struct drm_device *dev,
- @connector: DRM connector
- This function increments the connector's refcount.
- Returns:
*/
- The connector.
-static inline void drm_connector_get(struct drm_connector *connector) +static inline struct drm_connector *drm_connector_get(struct drm_connector *connector) { drm_mode_object_get(&connector->base);
- return connector;
}
/**
From: Ville Syrjälä ville.syrjala@linux.intel.com
To avoid having to deference plane_state->vma during the commit phase of plane updates, let's store the vma gtt offset (or the bus address when we need it) in the plane state. This is crucial for doing the modeset operations during GPU reset as as plane_state->vma gets cleared when we duplicate the state and we won't be calling .prepare_fb() during GPU reset plane commits.
Signed-off-by: Ville Syrjälä ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/intel_display.c | 38 +++++++++++++++++++++--------------- drivers/gpu/drm/i915/intel_drv.h | 6 +----- drivers/gpu/drm/i915/intel_sprite.c | 8 ++++---- 3 files changed, 27 insertions(+), 25 deletions(-)
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 1016afebef27..0ff3f254ee58 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2744,7 +2744,7 @@ intel_find_initial_plane_obj(struct intel_crtc *intel_crtc, if (!state->vma) continue;
- if (intel_plane_ggtt_offset(state) == plane_config->base) { + if (state->gtt_offset == plane_config->base) { fb = c->primary->fb; drm_framebuffer_reference(fb); goto valid_fb; @@ -2771,6 +2771,8 @@ intel_find_initial_plane_obj(struct intel_crtc *intel_crtc, mutex_lock(&dev->struct_mutex); intel_state->vma = intel_pin_and_fence_fb_obj(fb, primary->state->rotation); + intel_state->gtt_offset = i915_ggtt_offset(intel_state->vma); + mutex_unlock(&dev->struct_mutex); if (IS_ERR(intel_state->vma)) { DRM_ERROR("failed to pin boot fb on pipe %d: %li\n", @@ -3122,19 +3124,16 @@ static void i9xx_update_primary_plane(struct intel_plane *primary, I915_WRITE_FW(DSPSTRIDE(plane), fb->pitches[0]); if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) { I915_WRITE_FW(DSPSURF(plane), - intel_plane_ggtt_offset(plane_state) + - crtc->dspaddr_offset); + plane_state->gtt_offset + crtc->dspaddr_offset); I915_WRITE_FW(DSPOFFSET(plane), (y << 16) | x); } else if (INTEL_GEN(dev_priv) >= 4) { I915_WRITE_FW(DSPSURF(plane), - intel_plane_ggtt_offset(plane_state) + - crtc->dspaddr_offset); + plane_state->gtt_offset + crtc->dspaddr_offset); I915_WRITE_FW(DSPTILEOFF(plane), (y << 16) | x); I915_WRITE_FW(DSPLINOFF(plane), linear_offset); } else { I915_WRITE_FW(DSPADDR(plane), - intel_plane_ggtt_offset(plane_state) + - crtc->dspaddr_offset); + plane_state->gtt_offset + crtc->dspaddr_offset); } POSTING_READ_FW(reg);
@@ -3395,7 +3394,7 @@ static void skylake_update_primary_plane(struct intel_plane *plane, }
I915_WRITE_FW(PLANE_SURF(pipe, plane_id), - intel_plane_ggtt_offset(plane_state) + surf_addr); + plane_state->gtt_offset + surf_addr);
POSTING_READ_FW(PLANE_SURF(pipe, plane_id));
@@ -9202,15 +9201,9 @@ static u32 intel_cursor_base(const struct intel_plane_state *plane_state) struct drm_i915_private *dev_priv = to_i915(plane_state->base.plane->dev); const struct drm_framebuffer *fb = plane_state->base.fb; - const struct drm_i915_gem_object *obj = intel_fb_obj(fb); u32 base;
- if (INTEL_INFO(dev_priv)->cursor_needs_physical) - base = obj->phys_handle->busaddr; - else - base = intel_plane_ggtt_offset(plane_state); - - base += plane_state->main.offset; + base = plane_state->gtt_offset + plane_state->main.offset;
/* ILK+ do this automagically */ if (HAS_GMCH_DISPLAY(dev_priv) && @@ -10863,8 +10856,11 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
work->old_vma = to_intel_plane_state(primary->state)->vma; to_intel_plane_state(primary->state)->vma = vma; + to_intel_plane_state(primary->state)->gtt_offset = + i915_ggtt_offset(vma);
- work->gtt_offset = i915_ggtt_offset(vma) + intel_crtc->dspaddr_offset; + work->gtt_offset = to_intel_plane_state(primary->state)->gtt_offset + + intel_crtc->dspaddr_offset; work->rotation = crtc->primary->state->rotation;
/* @@ -10920,6 +10916,8 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, i915_add_request(request); cleanup_unpin: to_intel_plane_state(primary->state)->vma = work->old_vma; + to_intel_plane_state(primary->state)->gtt_offset = + i915_ggtt_offset(work->old_vma); intel_unpin_fb_vma(vma); cleanup_pending: atomic_dec(&intel_crtc->unpin_work_count); @@ -13361,6 +13359,8 @@ intel_prepare_plane_fb(struct drm_plane *plane, DRM_DEBUG_KMS("failed to attach phys object\n"); return ret; } + to_intel_plane_state(new_state)->gtt_offset = + obj->phys_handle->busaddr; } else { struct i915_vma *vma;
@@ -13371,6 +13371,8 @@ intel_prepare_plane_fb(struct drm_plane *plane, }
to_intel_plane_state(new_state)->vma = vma; + to_intel_plane_state(new_state)->gtt_offset = + i915_ggtt_offset(vma); } }
@@ -13680,6 +13682,8 @@ intel_legacy_cursor_update(struct drm_plane *plane, DRM_DEBUG_KMS("failed to attach phys object\n"); goto out_unlock; } + to_intel_plane_state(new_plane_state)->gtt_offset = + intel_fb_obj(fb)->phys_handle->busaddr; } else { struct i915_vma *vma;
@@ -13692,6 +13696,8 @@ intel_legacy_cursor_update(struct drm_plane *plane, }
to_intel_plane_state(new_plane_state)->vma = vma; + to_intel_plane_state(new_plane_state)->gtt_offset = + i915_ggtt_offset(vma); }
old_fb = old_plane_state->fb; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 4be10983e7cc..e72a8e29a2b0 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -405,6 +405,7 @@ struct intel_plane_state { struct drm_plane_state base; struct drm_rect clip; struct i915_vma *vma; + u32 gtt_offset; /* GGTT offset, or bus address */
struct { u32 offset; @@ -1508,11 +1509,6 @@ void intel_mode_from_pipe_config(struct drm_display_mode *mode, int skl_update_scaler_crtc(struct intel_crtc_state *crtc_state); int skl_max_scale(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state);
-static inline u32 intel_plane_ggtt_offset(const struct intel_plane_state *state) -{ - return i915_ggtt_offset(state->vma); -} - u32 skl_plane_ctl(const struct intel_crtc_state *crtc_state, const struct intel_plane_state *plane_state); u32 skl_plane_stride(const struct drm_framebuffer *fb, int plane, diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index 697b95016c7a..aed4fa833b48 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -300,7 +300,7 @@ skl_update_plane(struct intel_plane *plane,
I915_WRITE_FW(PLANE_CTL(pipe, plane_id), plane_ctl); I915_WRITE_FW(PLANE_SURF(pipe, plane_id), - intel_plane_ggtt_offset(plane_state) + surf_addr); + plane_state->gtt_offset + surf_addr); POSTING_READ_FW(PLANE_SURF(pipe, plane_id));
spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); @@ -477,7 +477,7 @@ vlv_update_plane(struct intel_plane *plane, I915_WRITE_FW(SPSIZE(pipe, plane_id), (crtc_h << 16) | crtc_w); I915_WRITE_FW(SPCNTR(pipe, plane_id), sprctl); I915_WRITE_FW(SPSURF(pipe, plane_id), - intel_plane_ggtt_offset(plane_state) + sprsurf_offset); + plane_state->gtt_offset + sprsurf_offset); POSTING_READ_FW(SPSURF(pipe, plane_id));
spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); @@ -615,7 +615,7 @@ ivb_update_plane(struct intel_plane *plane, I915_WRITE_FW(SPRSCALE(pipe), sprscale); I915_WRITE_FW(SPRCTL(pipe), sprctl); I915_WRITE_FW(SPRSURF(pipe), - intel_plane_ggtt_offset(plane_state) + sprsurf_offset); + plane_state->gtt_offset + sprsurf_offset); POSTING_READ_FW(SPRSURF(pipe));
spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); @@ -747,7 +747,7 @@ g4x_update_plane(struct intel_plane *plane, I915_WRITE_FW(DVSSCALE(pipe), dvsscale); I915_WRITE_FW(DVSCNTR(pipe), dvscntr); I915_WRITE_FW(DVSSURF(pipe), - intel_plane_ggtt_offset(plane_state) + dvssurf_offset); + plane_state->gtt_offset + dvssurf_offset); POSTING_READ_FW(DVSSURF(pipe));
spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
From: Ville Syrjälä ville.syrjala@linux.intel.com
Split intel_atomic_commit_tail() into a lower level function that does the actual commit, and a higher level one that waits for the dependencies and signals the commit as done. We'll reuse the lower level function to perform commits during GPU resets.
Signed-off-by: Ville Syrjälä ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/intel_display.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-)
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 0ff3f254ee58..e9c85d7cbb3e 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -13021,7 +13021,7 @@ static void intel_atomic_helper_free_state_worker(struct work_struct *work) intel_atomic_helper_free_state(dev_priv); }
-static void intel_atomic_commit_tail(struct drm_atomic_state *state) +static void __intel_atomic_commit_tail(struct drm_atomic_state *state) { struct drm_device *dev = state->dev; struct intel_atomic_state *intel_state = to_intel_atomic_state(state); @@ -13034,8 +13034,6 @@ static void intel_atomic_commit_tail(struct drm_atomic_state *state) unsigned crtc_vblank_mask = 0; int i;
- drm_atomic_helper_wait_for_dependencies(state); - if (intel_state->modeset) intel_display_power_get(dev_priv, POWER_DOMAIN_MODESET);
@@ -13160,8 +13158,6 @@ static void intel_atomic_commit_tail(struct drm_atomic_state *state) if (intel_state->modeset && intel_can_enable_sagv(state)) intel_enable_sagv(dev_priv);
- drm_atomic_helper_commit_hw_done(state); - if (intel_state->modeset) { /* As one of the primary mmio accessors, KMS has a high * likelihood of triggering bugs in unclaimed access. After we @@ -13172,6 +13168,18 @@ static void intel_atomic_commit_tail(struct drm_atomic_state *state) intel_uncore_arm_unclaimed_mmio_detection(dev_priv); intel_display_power_put(dev_priv, POWER_DOMAIN_MODESET); } +} + +static void intel_atomic_commit_tail(struct drm_atomic_state *state) +{ + struct drm_device *dev = state->dev; + struct drm_i915_private *dev_priv = to_i915(dev); + + drm_atomic_helper_wait_for_dependencies(state); + + __intel_atomic_commit_tail(state); + + drm_atomic_helper_commit_hw_done(state);
mutex_lock(&dev->struct_mutex); drm_atomic_helper_cleanup_planes(dev, state);
From: Ville Syrjälä ville.syrjala@linux.intel.com
For i915 GPU reset handling we'll want to be able to duplicate the state that was last commited to the hardware. For that purpose let's start to track the commited state for each object and provide a way to duplicate the commmited state into a new drm_atomic_state. The locking for .commited_state must to be provided by the driver.
drm_atomic_helper_duplicate_commited_state() duplicates the state to both old_state and new_state. For the purposes of i915 GPU reset we would only need one of them, but we actually need two top level states; one for disabling everything (which would need the duplicated state to be old_state), and another to reenable everything (which would need the duplicated state to be new_state). So to make it less comples I figured I'd just always duplicate both. Might want to rethink this if for no other reason that reducing the chances of memory allocation failure. Due to the double state duplication we need drm_atomic_helper_clean_commited_state() to clean up the duplicated old_state since that's not handled by the normal drm_atomic_state cleanup code.
TODO: do we want this in the helper, or maybe it should be just in i915?
v2: s/commited/committed/ everywhere (checkpatch) Handle state duplication errors better v3: Even more care in dealing with memory allocation errors Handle private objs too Deal with the potential ordering issues between swap_state() and hw_done() by keeping track of which state was swapped in last
Signed-off-by: Ville Syrjälä ville.syrjala@linux.intel.com --- drivers/gpu/drm/drm_atomic.c | 1 + drivers/gpu/drm/drm_atomic_helper.c | 231 ++++++++++++++++++++++++++++++++++++ include/drm/drm_atomic.h | 4 + include/drm/drm_atomic_helper.h | 8 ++ include/drm/drm_connector.h | 11 ++ include/drm/drm_crtc.h | 11 ++ include/drm/drm_plane.h | 11 ++ 7 files changed, 277 insertions(+)
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 56925b93f598..e1578d50d66f 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -1020,6 +1020,7 @@ drm_atomic_private_obj_init(struct drm_private_obj *obj, memset(obj, 0, sizeof(*obj));
obj->state = state; + obj->committed_state = state; obj->funcs = funcs; } EXPORT_SYMBOL(drm_atomic_private_obj_init); diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index f0887f231fb8..c3d02f12cd5d 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -1815,6 +1815,11 @@ void drm_atomic_helper_wait_for_dependencies(struct drm_atomic_state *old_state) } EXPORT_SYMBOL(drm_atomic_helper_wait_for_dependencies);
+static bool state_seqno_after(unsigned int a, unsigned int b) +{ + return (int)(b - a) < 0; +} + /** * drm_atomic_helper_commit_hw_done - setup possible nonblocking commit * @old_state: atomic state object with old state structures @@ -1833,11 +1838,39 @@ EXPORT_SYMBOL(drm_atomic_helper_wait_for_dependencies); void drm_atomic_helper_commit_hw_done(struct drm_atomic_state *old_state) { struct drm_crtc *crtc; + struct drm_plane *plane; + struct drm_connector *connector; + struct drm_private_obj *obj; struct drm_crtc_state *new_crtc_state; + struct drm_plane_state *new_plane_state; + struct drm_connector_state *new_connector_state; + struct drm_private_state *new_obj_state; struct drm_crtc_commit *commit; int i; + static DEFINE_SPINLOCK(committed_state_lock); + + spin_lock(&committed_state_lock); + + for_each_new_plane_in_state(old_state, plane, new_plane_state, i) { + if (plane->committed_state && + state_seqno_after(new_plane_state->seqno, + plane->committed_state->seqno)) + plane->committed_state = new_plane_state; + } + + for_each_new_connector_in_state(old_state, connector, new_connector_state, i) { + if (connector->committed_state && + state_seqno_after(new_connector_state->seqno, + connector->committed_state->seqno)) + connector->committed_state = new_connector_state; + }
for_each_new_crtc_in_state(old_state, crtc, new_crtc_state, i) { + if (crtc->committed_state && + state_seqno_after(new_crtc_state->seqno, + crtc->committed_state->seqno)) + crtc->committed_state = new_crtc_state; + commit = old_state->crtcs[i].commit; if (!commit) continue; @@ -1846,6 +1879,15 @@ void drm_atomic_helper_commit_hw_done(struct drm_atomic_state *old_state) WARN_ON(new_crtc_state->event); complete_all(&commit->hw_done); } + + for_each_new_private_obj_in_state(old_state, obj, new_obj_state, i) { + if (obj->committed_state && + state_seqno_after(new_obj_state->seqno, + obj->committed_state->seqno)) + obj->committed_state = new_obj_state; + } + + spin_unlock(&committed_state_lock); } EXPORT_SYMBOL(drm_atomic_helper_commit_hw_done);
@@ -2296,6 +2338,7 @@ void drm_atomic_helper_swap_state(struct drm_atomic_state *state,
old_conn_state->state = state; new_conn_state->state = NULL; + new_conn_state->seqno = ++connector->state_seqno;
__drm_atomic_state_connector(state, i)->state = old_conn_state; connector->state = new_conn_state; @@ -2309,6 +2352,7 @@ void drm_atomic_helper_swap_state(struct drm_atomic_state *state,
state->crtcs[i].state = old_crtc_state; crtc->state = new_crtc_state; + new_crtc_state->seqno = ++crtc->state_seqno;
if (state->crtcs[i].commit) { spin_lock(&crtc->commit_lock); @@ -2325,6 +2369,7 @@ void drm_atomic_helper_swap_state(struct drm_atomic_state *state,
old_plane_state->state = state; new_plane_state->state = NULL; + new_plane_state->seqno = ++plane->state_seqno;
state->planes[i].state = old_plane_state; plane->state = new_plane_state; @@ -2335,6 +2380,7 @@ void drm_atomic_helper_swap_state(struct drm_atomic_state *state,
old_obj_state->state = state; new_obj_state->state = NULL; + new_obj_state->seqno = ++obj->state_seqno;
__drm_atomic_state_private_obj(state, i)->state = old_obj_state; obj->state = new_obj_state; @@ -3582,6 +3628,7 @@ __drm_atomic_helper_connector_reset(struct drm_connector *connector, conn_state->connector = connector;
connector->state = conn_state; + connector->committed_state = conn_state; } EXPORT_SYMBOL(__drm_atomic_helper_connector_reset);
@@ -3740,6 +3787,189 @@ drm_atomic_helper_duplicate_state(struct drm_device *dev, } EXPORT_SYMBOL(drm_atomic_helper_duplicate_state);
+struct drm_atomic_state * +drm_atomic_helper_duplicate_committed_state(struct drm_device *dev) +{ + struct drm_atomic_state *state; + struct drm_connector_list_iter conn_iter; + struct drm_connector *conn; + struct drm_plane *plane; + struct drm_crtc *crtc; + int err = 0; + + state = drm_atomic_state_alloc(dev); + if (!state) + return ERR_PTR(-ENOMEM); + + drm_for_each_plane(plane, dev) { + struct drm_plane_state *old_state, *new_state; + int i = drm_plane_index(plane); + + old_state = plane->funcs->atomic_duplicate_state(plane, plane->committed_state); + if (!old_state) { + err = -ENOMEM; + goto free; + } + new_state = plane->funcs->atomic_duplicate_state(plane, plane->committed_state); + if (!new_state) { + plane->funcs->atomic_destroy_state(plane, old_state); + err = -ENOMEM; + goto free; + } + + state->planes[i].state = new_state; + state->planes[i].old_state = old_state; + state->planes[i].new_state = new_state; + state->planes[i].ptr = plane; + + old_state->state = state; + } + + drm_for_each_crtc(crtc, dev) { + struct drm_crtc_state *old_state, *new_state; + int i = drm_crtc_index(crtc); + + old_state = crtc->funcs->atomic_duplicate_state(crtc, crtc->committed_state); + if (!old_state) { + err = -ENOMEM; + goto free; + } + new_state = crtc->funcs->atomic_duplicate_state(crtc, crtc->committed_state); + if (!new_state) { + crtc->funcs->atomic_destroy_state(crtc, old_state); + err = -ENOMEM; + goto free; + } + + state->crtcs[i].state = new_state; + state->crtcs[i].old_state = old_state; + state->crtcs[i].new_state = new_state; + state->crtcs[i].ptr = crtc; + + old_state->state = state; + } + + drm_connector_list_iter_begin(dev, &conn_iter); + drm_for_each_connector_iter(conn, &conn_iter) { + struct drm_connector_state *old_state, *new_state; + struct __drm_connectors_state *c; + int i = drm_connector_index(conn); + + err = drm_dynarray_reserve(&state->connectors, i); + if (err) + break; + + old_state = conn->funcs->atomic_duplicate_state(conn, conn->committed_state); + if (!old_state) { + err = -ENOMEM; + break; + } + new_state = conn->funcs->atomic_duplicate_state(conn, conn->committed_state); + if (!new_state) { + conn->funcs->atomic_destroy_state(conn, old_state); + err = -ENOMEM; + break; + } + + state->num_connector = state->connectors.num_elems; + + c = __drm_atomic_state_connector(state, i); + + c->state = new_state; + c->old_state = old_state; + c->new_state = new_state; + c->ptr = drm_connector_get(conn); + + old_state->state = state; + } + drm_connector_list_iter_end(&conn_iter); + +free: + if (err < 0) { + drm_atomic_helper_clean_committed_state(state); + drm_atomic_state_put(state); + state = ERR_PTR(err); + } + + return state; +} +EXPORT_SYMBOL(drm_atomic_helper_duplicate_committed_state); + +int drm_atomic_helper_duplicate_private_obj_committed_state(struct drm_atomic_state *state, + struct drm_private_obj *obj) +{ + struct drm_private_state *old_state, *new_state; + struct __drm_private_objs_state *p; + int ret, i = state->num_private_objs; + + ret = drm_dynarray_reserve(&state->private_objs, i); + if (ret) + return ret; + + old_state = obj->funcs->atomic_duplicate_state(obj, obj->committed_state); + if (!old_state) + return -ENOMEM; + + new_state = obj->funcs->atomic_duplicate_state(obj, obj->committed_state); + if (!new_state) { + obj->funcs->atomic_destroy_state(obj, obj->committed_state); + return -ENOMEM; + } + + state->num_private_objs = state->private_objs.num_elems; + + p = __drm_atomic_state_private_obj(state, i); + + p->state = new_state; + p->old_state = old_state; + p->new_state = new_state; + p->ptr = obj; + + old_state->state = state; + + return 0; +} +EXPORT_SYMBOL(drm_atomic_helper_duplicate_private_obj_committed_state); + +void +drm_atomic_helper_clean_committed_state(struct drm_atomic_state *state) +{ + struct drm_plane *plane; + struct drm_crtc *crtc; + struct drm_connector *conn; + struct drm_plane_state *plane_state; + struct drm_crtc_state *crtc_state; + struct drm_connector_state *conn_state; + struct drm_private_obj *obj; + struct drm_private_state *obj_state; + int i; + + /* restore the correct state->state */ + for_each_new_plane_in_state(state, plane, plane_state, i) { + plane->funcs->atomic_destroy_state(plane, state->planes[i].old_state); + state->planes[i].old_state = NULL; + } + for_each_new_crtc_in_state(state, crtc, crtc_state, i) { + crtc->funcs->atomic_destroy_state(crtc, state->crtcs[i].old_state); + state->crtcs[i].old_state = NULL; + } + for_each_new_connector_in_state(state, conn, conn_state, i) { + struct __drm_connectors_state *c = + __drm_atomic_state_connector(state, i); + + conn->funcs->atomic_destroy_state(conn, c->old_state); + c->old_state = NULL; + } + for_each_new_private_obj_in_state(state, obj, obj_state, i) { + struct __drm_private_objs_state *p = + __drm_atomic_state_private_obj(state, i); + + obj->funcs->atomic_destroy_state(obj, p->old_state); + p->old_state = NULL; + } +} +EXPORT_SYMBOL(drm_atomic_helper_clean_committed_state); + /** * __drm_atomic_helper_connector_destroy_state - release connector state * @state: connector state object to release @@ -3856,6 +4086,7 @@ EXPORT_SYMBOL(drm_atomic_helper_legacy_gamma_set); * __drm_atomic_helper_private_duplicate_state - copy atomic private state * @obj: CRTC object * @state: new private object state + * @old_state: old private object state * * Copies atomic state from a private objects's current state and resets inferred values. * This is useful for drivers that subclass the private state. diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h index 0e6c54b3e0af..9ff4fb46d500 100644 --- a/include/drm/drm_atomic.h +++ b/include/drm/drm_atomic.h @@ -194,12 +194,16 @@ struct drm_private_state_funcs {
struct drm_private_obj { struct drm_private_state *state; + struct drm_private_state *committed_state;
const struct drm_private_state_funcs *funcs; + + unsigned int state_seqno; };
struct drm_private_state { struct drm_atomic_state *state; + unsigned int seqno; };
struct __drm_private_objs_state { diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h index b799687a4b09..3a609bbb5818 100644 --- a/include/drm/drm_atomic_helper.h +++ b/include/drm/drm_atomic_helper.h @@ -185,6 +185,14 @@ drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector, struct drm_atomic_state * drm_atomic_helper_duplicate_state(struct drm_device *dev, struct drm_modeset_acquire_ctx *ctx); +struct drm_atomic_state * +drm_atomic_helper_duplicate_committed_state(struct drm_device *dev); +struct drm_private_obj; +int +drm_atomic_helper_duplicate_private_obj_committed_state(struct drm_atomic_state *state, + struct drm_private_obj *obj); +void +drm_atomic_helper_clean_committed_state(struct drm_atomic_state *state); void __drm_atomic_helper_connector_destroy_state(struct drm_connector_state *state); void drm_atomic_helper_connector_destroy_state(struct drm_connector *connector, diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index 8f26166f78b4..a38ba05db4fa 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -306,6 +306,8 @@ struct drm_tv_connector_state { struct drm_connector_state { struct drm_connector *connector;
+ unsigned int seqno; + /** * @crtc: CRTC to connect connector to, NULL if disabled. * @@ -707,6 +709,8 @@ struct drm_connector {
char *name;
+ unsigned int state_seqno; + /** * @mutex: Lock for general connector state, but currently only protects * @registered. Most of the connector state is still protected by @@ -868,6 +872,13 @@ struct drm_connector { */ struct drm_connector_state *state;
+ /** + * @committed_state: + * + * Current committed atomic state for this connector. + */ + struct drm_connector_state *committed_state; + /* DisplayID bits */ bool has_tile; struct drm_tile_group *tile_group; diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 8bfbc54660ab..2a1897d76c71 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -108,6 +108,8 @@ struct drm_plane_helper_funcs; struct drm_crtc_state { struct drm_crtc *crtc;
+ unsigned int seqno; + bool enable; bool active;
@@ -750,6 +752,8 @@ struct drm_crtc {
char *name;
+ unsigned int state_seqno; + /** * @mutex: * @@ -816,6 +820,13 @@ struct drm_crtc { struct drm_crtc_state *state;
/** + * @committed_state: + * + * Current committed atomic state for this CRTC. + */ + struct drm_crtc_state *committed_state; + + /** * @commit_list: * * List of &drm_crtc_commit structures tracking pending commits. diff --git a/include/drm/drm_plane.h b/include/drm/drm_plane.h index 08ad4b58adbe..ff3495705e63 100644 --- a/include/drm/drm_plane.h +++ b/include/drm/drm_plane.h @@ -59,6 +59,8 @@ struct drm_modeset_acquire_ctx; struct drm_plane_state { struct drm_plane *plane;
+ unsigned int seqno; + /** * @crtc: * @@ -470,6 +472,8 @@ struct drm_plane {
char *name;
+ unsigned int state_seqno; + /** * @mutex: * @@ -522,6 +526,13 @@ struct drm_plane { */ struct drm_plane_state *state;
+ /** + * @committed_state: + * + * Current committed atomic state for this plane. + */ + struct drm_plane_state *committed_state; + struct drm_property *zpos_property; struct drm_property *rotation_property; };
On Thu, Jul 06, 2017 at 11:24:41PM +0300, ville.syrjala@linux.intel.com wrote:
From: Ville Syrjälä ville.syrjala@linux.intel.com
For i915 GPU reset handling we'll want to be able to duplicate the state that was last commited to the hardware. For that purpose let's start to track the commited state for each object and provide a way to duplicate the commmited state into a new drm_atomic_state. The locking for .commited_state must to be provided by the driver.
drm_atomic_helper_duplicate_commited_state() duplicates the state to both old_state and new_state. For the purposes of i915 GPU reset we would only need one of them, but we actually need two top level states; one for disabling everything (which would need the duplicated state to be old_state), and another to reenable everything (which would need the duplicated state to be new_state). So to make it less comples I figured I'd just always duplicate both. Might want to rethink this if for no other reason that reducing the chances of memory allocation failure. Due to the double state duplication we need drm_atomic_helper_clean_commited_state() to clean up the duplicated old_state since that's not handled by the normal drm_atomic_state cleanup code.
TODO: do we want this in the helper, or maybe it should be just in i915?
v2: s/commited/committed/ everywhere (checkpatch) Handle state duplication errors better v3: Even more care in dealing with memory allocation errors Handle private objs too Deal with the potential ordering issues between swap_state() and hw_done() by keeping track of which state was swapped in last
Signed-off-by: Ville Syrjälä ville.syrjala@linux.intel.com
I still don't get why we need to duplicate the committed state for gpu reset. When I said I'm not against adding all that complexity long-term I meant when we actually really need it. Imo g4x gpu reset isn't a good justification for that, reworking the atomic world for that seems massively out of proportion.
Why exactly can't we do this simpler? I still don't get that part. Is there really no solution that doesn't break atomic's current assumption that commits are fully ordered on a given crtc? -Daniel
drivers/gpu/drm/drm_atomic.c | 1 + drivers/gpu/drm/drm_atomic_helper.c | 231 ++++++++++++++++++++++++++++++++++++ include/drm/drm_atomic.h | 4 + include/drm/drm_atomic_helper.h | 8 ++ include/drm/drm_connector.h | 11 ++ include/drm/drm_crtc.h | 11 ++ include/drm/drm_plane.h | 11 ++ 7 files changed, 277 insertions(+)
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 56925b93f598..e1578d50d66f 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -1020,6 +1020,7 @@ drm_atomic_private_obj_init(struct drm_private_obj *obj, memset(obj, 0, sizeof(*obj));
obj->state = state;
- obj->committed_state = state; obj->funcs = funcs;
} EXPORT_SYMBOL(drm_atomic_private_obj_init); diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index f0887f231fb8..c3d02f12cd5d 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -1815,6 +1815,11 @@ void drm_atomic_helper_wait_for_dependencies(struct drm_atomic_state *old_state) } EXPORT_SYMBOL(drm_atomic_helper_wait_for_dependencies);
+static bool state_seqno_after(unsigned int a, unsigned int b) +{
- return (int)(b - a) < 0;
+}
/**
- drm_atomic_helper_commit_hw_done - setup possible nonblocking commit
- @old_state: atomic state object with old state structures
@@ -1833,11 +1838,39 @@ EXPORT_SYMBOL(drm_atomic_helper_wait_for_dependencies); void drm_atomic_helper_commit_hw_done(struct drm_atomic_state *old_state) { struct drm_crtc *crtc;
struct drm_plane *plane;
struct drm_connector *connector;
struct drm_private_obj *obj; struct drm_crtc_state *new_crtc_state;
struct drm_plane_state *new_plane_state;
struct drm_connector_state *new_connector_state;
struct drm_private_state *new_obj_state; struct drm_crtc_commit *commit; int i;
static DEFINE_SPINLOCK(committed_state_lock);
spin_lock(&committed_state_lock);
for_each_new_plane_in_state(old_state, plane, new_plane_state, i) {
if (plane->committed_state &&
state_seqno_after(new_plane_state->seqno,
plane->committed_state->seqno))
plane->committed_state = new_plane_state;
}
for_each_new_connector_in_state(old_state, connector, new_connector_state, i) {
if (connector->committed_state &&
state_seqno_after(new_connector_state->seqno,
connector->committed_state->seqno))
connector->committed_state = new_connector_state;
}
for_each_new_crtc_in_state(old_state, crtc, new_crtc_state, i) {
if (crtc->committed_state &&
state_seqno_after(new_crtc_state->seqno,
crtc->committed_state->seqno))
crtc->committed_state = new_crtc_state;
commit = old_state->crtcs[i].commit; if (!commit) continue;
@@ -1846,6 +1879,15 @@ void drm_atomic_helper_commit_hw_done(struct drm_atomic_state *old_state) WARN_ON(new_crtc_state->event); complete_all(&commit->hw_done); }
- for_each_new_private_obj_in_state(old_state, obj, new_obj_state, i) {
if (obj->committed_state &&
state_seqno_after(new_obj_state->seqno,
obj->committed_state->seqno))
obj->committed_state = new_obj_state;
- }
- spin_unlock(&committed_state_lock);
} EXPORT_SYMBOL(drm_atomic_helper_commit_hw_done);
@@ -2296,6 +2338,7 @@ void drm_atomic_helper_swap_state(struct drm_atomic_state *state,
old_conn_state->state = state; new_conn_state->state = NULL;
new_conn_state->seqno = ++connector->state_seqno;
__drm_atomic_state_connector(state, i)->state = old_conn_state; connector->state = new_conn_state;
@@ -2309,6 +2352,7 @@ void drm_atomic_helper_swap_state(struct drm_atomic_state *state,
state->crtcs[i].state = old_crtc_state; crtc->state = new_crtc_state;
new_crtc_state->seqno = ++crtc->state_seqno;
if (state->crtcs[i].commit) { spin_lock(&crtc->commit_lock);
@@ -2325,6 +2369,7 @@ void drm_atomic_helper_swap_state(struct drm_atomic_state *state,
old_plane_state->state = state; new_plane_state->state = NULL;
new_plane_state->seqno = ++plane->state_seqno;
state->planes[i].state = old_plane_state; plane->state = new_plane_state;
@@ -2335,6 +2380,7 @@ void drm_atomic_helper_swap_state(struct drm_atomic_state *state,
old_obj_state->state = state; new_obj_state->state = NULL;
new_obj_state->seqno = ++obj->state_seqno;
__drm_atomic_state_private_obj(state, i)->state = old_obj_state; obj->state = new_obj_state;
@@ -3582,6 +3628,7 @@ __drm_atomic_helper_connector_reset(struct drm_connector *connector, conn_state->connector = connector;
connector->state = conn_state;
- connector->committed_state = conn_state;
} EXPORT_SYMBOL(__drm_atomic_helper_connector_reset);
@@ -3740,6 +3787,189 @@ drm_atomic_helper_duplicate_state(struct drm_device *dev, } EXPORT_SYMBOL(drm_atomic_helper_duplicate_state);
+struct drm_atomic_state * +drm_atomic_helper_duplicate_committed_state(struct drm_device *dev) +{
- struct drm_atomic_state *state;
- struct drm_connector_list_iter conn_iter;
- struct drm_connector *conn;
- struct drm_plane *plane;
- struct drm_crtc *crtc;
- int err = 0;
- state = drm_atomic_state_alloc(dev);
- if (!state)
return ERR_PTR(-ENOMEM);
- drm_for_each_plane(plane, dev) {
struct drm_plane_state *old_state, *new_state;
int i = drm_plane_index(plane);
old_state = plane->funcs->atomic_duplicate_state(plane, plane->committed_state);
if (!old_state) {
err = -ENOMEM;
goto free;
}
new_state = plane->funcs->atomic_duplicate_state(plane, plane->committed_state);
if (!new_state) {
plane->funcs->atomic_destroy_state(plane, old_state);
err = -ENOMEM;
goto free;
}
state->planes[i].state = new_state;
state->planes[i].old_state = old_state;
state->planes[i].new_state = new_state;
state->planes[i].ptr = plane;
old_state->state = state;
- }
- drm_for_each_crtc(crtc, dev) {
struct drm_crtc_state *old_state, *new_state;
int i = drm_crtc_index(crtc);
old_state = crtc->funcs->atomic_duplicate_state(crtc, crtc->committed_state);
if (!old_state) {
err = -ENOMEM;
goto free;
}
new_state = crtc->funcs->atomic_duplicate_state(crtc, crtc->committed_state);
if (!new_state) {
crtc->funcs->atomic_destroy_state(crtc, old_state);
err = -ENOMEM;
goto free;
}
state->crtcs[i].state = new_state;
state->crtcs[i].old_state = old_state;
state->crtcs[i].new_state = new_state;
state->crtcs[i].ptr = crtc;
old_state->state = state;
- }
- drm_connector_list_iter_begin(dev, &conn_iter);
- drm_for_each_connector_iter(conn, &conn_iter) {
struct drm_connector_state *old_state, *new_state;
struct __drm_connectors_state *c;
int i = drm_connector_index(conn);
err = drm_dynarray_reserve(&state->connectors, i);
if (err)
break;
old_state = conn->funcs->atomic_duplicate_state(conn, conn->committed_state);
if (!old_state) {
err = -ENOMEM;
break;
}
new_state = conn->funcs->atomic_duplicate_state(conn, conn->committed_state);
if (!new_state) {
conn->funcs->atomic_destroy_state(conn, old_state);
err = -ENOMEM;
break;
}
state->num_connector = state->connectors.num_elems;
c = __drm_atomic_state_connector(state, i);
c->state = new_state;
c->old_state = old_state;
c->new_state = new_state;
c->ptr = drm_connector_get(conn);
old_state->state = state;
- }
- drm_connector_list_iter_end(&conn_iter);
+free:
- if (err < 0) {
drm_atomic_helper_clean_committed_state(state);
drm_atomic_state_put(state);
state = ERR_PTR(err);
- }
- return state;
+} +EXPORT_SYMBOL(drm_atomic_helper_duplicate_committed_state);
+int drm_atomic_helper_duplicate_private_obj_committed_state(struct drm_atomic_state *state,
struct drm_private_obj *obj)
+{
- struct drm_private_state *old_state, *new_state;
- struct __drm_private_objs_state *p;
- int ret, i = state->num_private_objs;
- ret = drm_dynarray_reserve(&state->private_objs, i);
- if (ret)
return ret;
- old_state = obj->funcs->atomic_duplicate_state(obj, obj->committed_state);
- if (!old_state)
return -ENOMEM;
- new_state = obj->funcs->atomic_duplicate_state(obj, obj->committed_state);
- if (!new_state) {
obj->funcs->atomic_destroy_state(obj, obj->committed_state);
return -ENOMEM;
- }
- state->num_private_objs = state->private_objs.num_elems;
- p = __drm_atomic_state_private_obj(state, i);
- p->state = new_state;
- p->old_state = old_state;
- p->new_state = new_state;
- p->ptr = obj;
- old_state->state = state;
- return 0;
+} +EXPORT_SYMBOL(drm_atomic_helper_duplicate_private_obj_committed_state);
+void +drm_atomic_helper_clean_committed_state(struct drm_atomic_state *state) +{
- struct drm_plane *plane;
- struct drm_crtc *crtc;
- struct drm_connector *conn;
- struct drm_plane_state *plane_state;
- struct drm_crtc_state *crtc_state;
- struct drm_connector_state *conn_state;
- struct drm_private_obj *obj;
- struct drm_private_state *obj_state;
- int i;
- /* restore the correct state->state */
- for_each_new_plane_in_state(state, plane, plane_state, i) {
plane->funcs->atomic_destroy_state(plane, state->planes[i].old_state);
state->planes[i].old_state = NULL;
- }
- for_each_new_crtc_in_state(state, crtc, crtc_state, i) {
crtc->funcs->atomic_destroy_state(crtc, state->crtcs[i].old_state);
state->crtcs[i].old_state = NULL;
- }
- for_each_new_connector_in_state(state, conn, conn_state, i) {
struct __drm_connectors_state *c =
__drm_atomic_state_connector(state, i);
conn->funcs->atomic_destroy_state(conn, c->old_state);
c->old_state = NULL;
- }
- for_each_new_private_obj_in_state(state, obj, obj_state, i) {
struct __drm_private_objs_state *p =
__drm_atomic_state_private_obj(state, i);
obj->funcs->atomic_destroy_state(obj, p->old_state);
p->old_state = NULL;
- }
+} +EXPORT_SYMBOL(drm_atomic_helper_clean_committed_state);
/**
- __drm_atomic_helper_connector_destroy_state - release connector state
- @state: connector state object to release
@@ -3856,6 +4086,7 @@ EXPORT_SYMBOL(drm_atomic_helper_legacy_gamma_set);
- __drm_atomic_helper_private_duplicate_state - copy atomic private state
- @obj: CRTC object
- @state: new private object state
- @old_state: old private object state
- Copies atomic state from a private objects's current state and resets inferred values.
- This is useful for drivers that subclass the private state.
diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h index 0e6c54b3e0af..9ff4fb46d500 100644 --- a/include/drm/drm_atomic.h +++ b/include/drm/drm_atomic.h @@ -194,12 +194,16 @@ struct drm_private_state_funcs {
struct drm_private_obj { struct drm_private_state *state;
struct drm_private_state *committed_state;
const struct drm_private_state_funcs *funcs;
unsigned int state_seqno;
};
struct drm_private_state { struct drm_atomic_state *state;
- unsigned int seqno;
};
struct __drm_private_objs_state { diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h index b799687a4b09..3a609bbb5818 100644 --- a/include/drm/drm_atomic_helper.h +++ b/include/drm/drm_atomic_helper.h @@ -185,6 +185,14 @@ drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector, struct drm_atomic_state * drm_atomic_helper_duplicate_state(struct drm_device *dev, struct drm_modeset_acquire_ctx *ctx); +struct drm_atomic_state * +drm_atomic_helper_duplicate_committed_state(struct drm_device *dev); +struct drm_private_obj; +int +drm_atomic_helper_duplicate_private_obj_committed_state(struct drm_atomic_state *state,
struct drm_private_obj *obj);
+void +drm_atomic_helper_clean_committed_state(struct drm_atomic_state *state); void __drm_atomic_helper_connector_destroy_state(struct drm_connector_state *state); void drm_atomic_helper_connector_destroy_state(struct drm_connector *connector, diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index 8f26166f78b4..a38ba05db4fa 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -306,6 +306,8 @@ struct drm_tv_connector_state { struct drm_connector_state { struct drm_connector *connector;
- unsigned int seqno;
- /**
- @crtc: CRTC to connect connector to, NULL if disabled.
@@ -707,6 +709,8 @@ struct drm_connector {
char *name;
- unsigned int state_seqno;
- /**
- @mutex: Lock for general connector state, but currently only protects
- @registered. Most of the connector state is still protected by
@@ -868,6 +872,13 @@ struct drm_connector { */ struct drm_connector_state *state;
- /**
* @committed_state:
*
* Current committed atomic state for this connector.
*/
- struct drm_connector_state *committed_state;
- /* DisplayID bits */ bool has_tile; struct drm_tile_group *tile_group;
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 8bfbc54660ab..2a1897d76c71 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -108,6 +108,8 @@ struct drm_plane_helper_funcs; struct drm_crtc_state { struct drm_crtc *crtc;
- unsigned int seqno;
- bool enable; bool active;
@@ -750,6 +752,8 @@ struct drm_crtc {
char *name;
- unsigned int state_seqno;
- /**
- @mutex:
@@ -816,6 +820,13 @@ struct drm_crtc { struct drm_crtc_state *state;
/**
* @committed_state:
*
* Current committed atomic state for this CRTC.
*/
- struct drm_crtc_state *committed_state;
- /**
- @commit_list:
- List of &drm_crtc_commit structures tracking pending commits.
diff --git a/include/drm/drm_plane.h b/include/drm/drm_plane.h index 08ad4b58adbe..ff3495705e63 100644 --- a/include/drm/drm_plane.h +++ b/include/drm/drm_plane.h @@ -59,6 +59,8 @@ struct drm_modeset_acquire_ctx; struct drm_plane_state { struct drm_plane *plane;
- unsigned int seqno;
- /**
- @crtc:
@@ -470,6 +472,8 @@ struct drm_plane {
char *name;
- unsigned int state_seqno;
- /**
- @mutex:
@@ -522,6 +526,13 @@ struct drm_plane { */ struct drm_plane_state *state;
- /**
* @committed_state:
*
* Current committed atomic state for this plane.
*/
- struct drm_plane_state *committed_state;
- struct drm_property *zpos_property; struct drm_property *rotation_property;
};
2.13.0
Intel-gfx mailing list Intel-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/intel-gfx
On Fri, Jul 07, 2017 at 02:03:38PM +0200, Daniel Vetter wrote:
On Thu, Jul 06, 2017 at 11:24:41PM +0300, ville.syrjala@linux.intel.com wrote:
From: Ville Syrjälä ville.syrjala@linux.intel.com
For i915 GPU reset handling we'll want to be able to duplicate the state that was last commited to the hardware. For that purpose let's start to track the commited state for each object and provide a way to duplicate the commmited state into a new drm_atomic_state. The locking for .commited_state must to be provided by the driver.
drm_atomic_helper_duplicate_commited_state() duplicates the state to both old_state and new_state. For the purposes of i915 GPU reset we would only need one of them, but we actually need two top level states; one for disabling everything (which would need the duplicated state to be old_state), and another to reenable everything (which would need the duplicated state to be new_state). So to make it less comples I figured I'd just always duplicate both. Might want to rethink this if for no other reason that reducing the chances of memory allocation failure. Due to the double state duplication we need drm_atomic_helper_clean_commited_state() to clean up the duplicated old_state since that's not handled by the normal drm_atomic_state cleanup code.
TODO: do we want this in the helper, or maybe it should be just in i915?
v2: s/commited/committed/ everywhere (checkpatch) Handle state duplication errors better v3: Even more care in dealing with memory allocation errors Handle private objs too Deal with the potential ordering issues between swap_state() and hw_done() by keeping track of which state was swapped in last
Signed-off-by: Ville Syrjälä ville.syrjala@linux.intel.com
I still don't get why we need to duplicate the committed state for gpu reset. When I said I'm not against adding all that complexity long-term I meant when we actually really need it. Imo g4x gpu reset isn't a good justification for that, reworking the atomic world for that seems massively out of proportion.
Well, I still don't see what's so "massive" about a couple of extra state pointers hanging around.
Also while doing that state duplication stuff, my old idea of splitting the crtc disable and enable phases into separate atomic commits popped up again in my head. For that being able to duplicate arbitrary states would seem like a nice thing to have. So the refactoring I had to do can have other uses.
Why exactly can't we do this simpler? I still don't get that part. Is there really no solution that doesn't break atomic's current assumption that commits are fully ordered on a given crtc?
From the point of view of the old and new states it doesn't actually
break that. The commits done from the reset path are essentially invisible to the normal modeset operation.
The one alternative proposed idea of allowing gem and kms sides go out of whack scares me a bit. I think that might land us in more trouble when I finally get around to making the video overlay a drm_plane.
And I think trying to keep the GPU reset paths as similar as possible between all the platforms would be a nice thing. Just whacking everything on the head with a hammer on one platform but not on another one seems to me like extra variation in behaviour that we don't necessarily want.
But like I said, if someone can come up with a better solution I probably wouldn't object too much. It's not going to be coming from me though since I have plenty of other things to do and vacation time is coming up very soon. So unless someone else comes up with something nice soon I think we should just go with my solution because a) it's already available, and b) works quite decently from what I can see.
-Daniel
drivers/gpu/drm/drm_atomic.c | 1 + drivers/gpu/drm/drm_atomic_helper.c | 231 ++++++++++++++++++++++++++++++++++++ include/drm/drm_atomic.h | 4 + include/drm/drm_atomic_helper.h | 8 ++ include/drm/drm_connector.h | 11 ++ include/drm/drm_crtc.h | 11 ++ include/drm/drm_plane.h | 11 ++ 7 files changed, 277 insertions(+)
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 56925b93f598..e1578d50d66f 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -1020,6 +1020,7 @@ drm_atomic_private_obj_init(struct drm_private_obj *obj, memset(obj, 0, sizeof(*obj));
obj->state = state;
- obj->committed_state = state; obj->funcs = funcs;
} EXPORT_SYMBOL(drm_atomic_private_obj_init); diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index f0887f231fb8..c3d02f12cd5d 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -1815,6 +1815,11 @@ void drm_atomic_helper_wait_for_dependencies(struct drm_atomic_state *old_state) } EXPORT_SYMBOL(drm_atomic_helper_wait_for_dependencies);
+static bool state_seqno_after(unsigned int a, unsigned int b) +{
- return (int)(b - a) < 0;
+}
/**
- drm_atomic_helper_commit_hw_done - setup possible nonblocking commit
- @old_state: atomic state object with old state structures
@@ -1833,11 +1838,39 @@ EXPORT_SYMBOL(drm_atomic_helper_wait_for_dependencies); void drm_atomic_helper_commit_hw_done(struct drm_atomic_state *old_state) { struct drm_crtc *crtc;
struct drm_plane *plane;
struct drm_connector *connector;
struct drm_private_obj *obj; struct drm_crtc_state *new_crtc_state;
struct drm_plane_state *new_plane_state;
struct drm_connector_state *new_connector_state;
struct drm_private_state *new_obj_state; struct drm_crtc_commit *commit; int i;
static DEFINE_SPINLOCK(committed_state_lock);
spin_lock(&committed_state_lock);
for_each_new_plane_in_state(old_state, plane, new_plane_state, i) {
if (plane->committed_state &&
state_seqno_after(new_plane_state->seqno,
plane->committed_state->seqno))
plane->committed_state = new_plane_state;
}
for_each_new_connector_in_state(old_state, connector, new_connector_state, i) {
if (connector->committed_state &&
state_seqno_after(new_connector_state->seqno,
connector->committed_state->seqno))
connector->committed_state = new_connector_state;
}
for_each_new_crtc_in_state(old_state, crtc, new_crtc_state, i) {
if (crtc->committed_state &&
state_seqno_after(new_crtc_state->seqno,
crtc->committed_state->seqno))
crtc->committed_state = new_crtc_state;
commit = old_state->crtcs[i].commit; if (!commit) continue;
@@ -1846,6 +1879,15 @@ void drm_atomic_helper_commit_hw_done(struct drm_atomic_state *old_state) WARN_ON(new_crtc_state->event); complete_all(&commit->hw_done); }
- for_each_new_private_obj_in_state(old_state, obj, new_obj_state, i) {
if (obj->committed_state &&
state_seqno_after(new_obj_state->seqno,
obj->committed_state->seqno))
obj->committed_state = new_obj_state;
- }
- spin_unlock(&committed_state_lock);
} EXPORT_SYMBOL(drm_atomic_helper_commit_hw_done);
@@ -2296,6 +2338,7 @@ void drm_atomic_helper_swap_state(struct drm_atomic_state *state,
old_conn_state->state = state; new_conn_state->state = NULL;
new_conn_state->seqno = ++connector->state_seqno;
__drm_atomic_state_connector(state, i)->state = old_conn_state; connector->state = new_conn_state;
@@ -2309,6 +2352,7 @@ void drm_atomic_helper_swap_state(struct drm_atomic_state *state,
state->crtcs[i].state = old_crtc_state; crtc->state = new_crtc_state;
new_crtc_state->seqno = ++crtc->state_seqno;
if (state->crtcs[i].commit) { spin_lock(&crtc->commit_lock);
@@ -2325,6 +2369,7 @@ void drm_atomic_helper_swap_state(struct drm_atomic_state *state,
old_plane_state->state = state; new_plane_state->state = NULL;
new_plane_state->seqno = ++plane->state_seqno;
state->planes[i].state = old_plane_state; plane->state = new_plane_state;
@@ -2335,6 +2380,7 @@ void drm_atomic_helper_swap_state(struct drm_atomic_state *state,
old_obj_state->state = state; new_obj_state->state = NULL;
new_obj_state->seqno = ++obj->state_seqno;
__drm_atomic_state_private_obj(state, i)->state = old_obj_state; obj->state = new_obj_state;
@@ -3582,6 +3628,7 @@ __drm_atomic_helper_connector_reset(struct drm_connector *connector, conn_state->connector = connector;
connector->state = conn_state;
- connector->committed_state = conn_state;
} EXPORT_SYMBOL(__drm_atomic_helper_connector_reset);
@@ -3740,6 +3787,189 @@ drm_atomic_helper_duplicate_state(struct drm_device *dev, } EXPORT_SYMBOL(drm_atomic_helper_duplicate_state);
+struct drm_atomic_state * +drm_atomic_helper_duplicate_committed_state(struct drm_device *dev) +{
- struct drm_atomic_state *state;
- struct drm_connector_list_iter conn_iter;
- struct drm_connector *conn;
- struct drm_plane *plane;
- struct drm_crtc *crtc;
- int err = 0;
- state = drm_atomic_state_alloc(dev);
- if (!state)
return ERR_PTR(-ENOMEM);
- drm_for_each_plane(plane, dev) {
struct drm_plane_state *old_state, *new_state;
int i = drm_plane_index(plane);
old_state = plane->funcs->atomic_duplicate_state(plane, plane->committed_state);
if (!old_state) {
err = -ENOMEM;
goto free;
}
new_state = plane->funcs->atomic_duplicate_state(plane, plane->committed_state);
if (!new_state) {
plane->funcs->atomic_destroy_state(plane, old_state);
err = -ENOMEM;
goto free;
}
state->planes[i].state = new_state;
state->planes[i].old_state = old_state;
state->planes[i].new_state = new_state;
state->planes[i].ptr = plane;
old_state->state = state;
- }
- drm_for_each_crtc(crtc, dev) {
struct drm_crtc_state *old_state, *new_state;
int i = drm_crtc_index(crtc);
old_state = crtc->funcs->atomic_duplicate_state(crtc, crtc->committed_state);
if (!old_state) {
err = -ENOMEM;
goto free;
}
new_state = crtc->funcs->atomic_duplicate_state(crtc, crtc->committed_state);
if (!new_state) {
crtc->funcs->atomic_destroy_state(crtc, old_state);
err = -ENOMEM;
goto free;
}
state->crtcs[i].state = new_state;
state->crtcs[i].old_state = old_state;
state->crtcs[i].new_state = new_state;
state->crtcs[i].ptr = crtc;
old_state->state = state;
- }
- drm_connector_list_iter_begin(dev, &conn_iter);
- drm_for_each_connector_iter(conn, &conn_iter) {
struct drm_connector_state *old_state, *new_state;
struct __drm_connectors_state *c;
int i = drm_connector_index(conn);
err = drm_dynarray_reserve(&state->connectors, i);
if (err)
break;
old_state = conn->funcs->atomic_duplicate_state(conn, conn->committed_state);
if (!old_state) {
err = -ENOMEM;
break;
}
new_state = conn->funcs->atomic_duplicate_state(conn, conn->committed_state);
if (!new_state) {
conn->funcs->atomic_destroy_state(conn, old_state);
err = -ENOMEM;
break;
}
state->num_connector = state->connectors.num_elems;
c = __drm_atomic_state_connector(state, i);
c->state = new_state;
c->old_state = old_state;
c->new_state = new_state;
c->ptr = drm_connector_get(conn);
old_state->state = state;
- }
- drm_connector_list_iter_end(&conn_iter);
+free:
- if (err < 0) {
drm_atomic_helper_clean_committed_state(state);
drm_atomic_state_put(state);
state = ERR_PTR(err);
- }
- return state;
+} +EXPORT_SYMBOL(drm_atomic_helper_duplicate_committed_state);
+int drm_atomic_helper_duplicate_private_obj_committed_state(struct drm_atomic_state *state,
struct drm_private_obj *obj)
+{
- struct drm_private_state *old_state, *new_state;
- struct __drm_private_objs_state *p;
- int ret, i = state->num_private_objs;
- ret = drm_dynarray_reserve(&state->private_objs, i);
- if (ret)
return ret;
- old_state = obj->funcs->atomic_duplicate_state(obj, obj->committed_state);
- if (!old_state)
return -ENOMEM;
- new_state = obj->funcs->atomic_duplicate_state(obj, obj->committed_state);
- if (!new_state) {
obj->funcs->atomic_destroy_state(obj, obj->committed_state);
return -ENOMEM;
- }
- state->num_private_objs = state->private_objs.num_elems;
- p = __drm_atomic_state_private_obj(state, i);
- p->state = new_state;
- p->old_state = old_state;
- p->new_state = new_state;
- p->ptr = obj;
- old_state->state = state;
- return 0;
+} +EXPORT_SYMBOL(drm_atomic_helper_duplicate_private_obj_committed_state);
+void +drm_atomic_helper_clean_committed_state(struct drm_atomic_state *state) +{
- struct drm_plane *plane;
- struct drm_crtc *crtc;
- struct drm_connector *conn;
- struct drm_plane_state *plane_state;
- struct drm_crtc_state *crtc_state;
- struct drm_connector_state *conn_state;
- struct drm_private_obj *obj;
- struct drm_private_state *obj_state;
- int i;
- /* restore the correct state->state */
- for_each_new_plane_in_state(state, plane, plane_state, i) {
plane->funcs->atomic_destroy_state(plane, state->planes[i].old_state);
state->planes[i].old_state = NULL;
- }
- for_each_new_crtc_in_state(state, crtc, crtc_state, i) {
crtc->funcs->atomic_destroy_state(crtc, state->crtcs[i].old_state);
state->crtcs[i].old_state = NULL;
- }
- for_each_new_connector_in_state(state, conn, conn_state, i) {
struct __drm_connectors_state *c =
__drm_atomic_state_connector(state, i);
conn->funcs->atomic_destroy_state(conn, c->old_state);
c->old_state = NULL;
- }
- for_each_new_private_obj_in_state(state, obj, obj_state, i) {
struct __drm_private_objs_state *p =
__drm_atomic_state_private_obj(state, i);
obj->funcs->atomic_destroy_state(obj, p->old_state);
p->old_state = NULL;
- }
+} +EXPORT_SYMBOL(drm_atomic_helper_clean_committed_state);
/**
- __drm_atomic_helper_connector_destroy_state - release connector state
- @state: connector state object to release
@@ -3856,6 +4086,7 @@ EXPORT_SYMBOL(drm_atomic_helper_legacy_gamma_set);
- __drm_atomic_helper_private_duplicate_state - copy atomic private state
- @obj: CRTC object
- @state: new private object state
- @old_state: old private object state
- Copies atomic state from a private objects's current state and resets inferred values.
- This is useful for drivers that subclass the private state.
diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h index 0e6c54b3e0af..9ff4fb46d500 100644 --- a/include/drm/drm_atomic.h +++ b/include/drm/drm_atomic.h @@ -194,12 +194,16 @@ struct drm_private_state_funcs {
struct drm_private_obj { struct drm_private_state *state;
struct drm_private_state *committed_state;
const struct drm_private_state_funcs *funcs;
unsigned int state_seqno;
};
struct drm_private_state { struct drm_atomic_state *state;
- unsigned int seqno;
};
struct __drm_private_objs_state { diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h index b799687a4b09..3a609bbb5818 100644 --- a/include/drm/drm_atomic_helper.h +++ b/include/drm/drm_atomic_helper.h @@ -185,6 +185,14 @@ drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector, struct drm_atomic_state * drm_atomic_helper_duplicate_state(struct drm_device *dev, struct drm_modeset_acquire_ctx *ctx); +struct drm_atomic_state * +drm_atomic_helper_duplicate_committed_state(struct drm_device *dev); +struct drm_private_obj; +int +drm_atomic_helper_duplicate_private_obj_committed_state(struct drm_atomic_state *state,
struct drm_private_obj *obj);
+void +drm_atomic_helper_clean_committed_state(struct drm_atomic_state *state); void __drm_atomic_helper_connector_destroy_state(struct drm_connector_state *state); void drm_atomic_helper_connector_destroy_state(struct drm_connector *connector, diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index 8f26166f78b4..a38ba05db4fa 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -306,6 +306,8 @@ struct drm_tv_connector_state { struct drm_connector_state { struct drm_connector *connector;
- unsigned int seqno;
- /**
- @crtc: CRTC to connect connector to, NULL if disabled.
@@ -707,6 +709,8 @@ struct drm_connector {
char *name;
- unsigned int state_seqno;
- /**
- @mutex: Lock for general connector state, but currently only protects
- @registered. Most of the connector state is still protected by
@@ -868,6 +872,13 @@ struct drm_connector { */ struct drm_connector_state *state;
- /**
* @committed_state:
*
* Current committed atomic state for this connector.
*/
- struct drm_connector_state *committed_state;
- /* DisplayID bits */ bool has_tile; struct drm_tile_group *tile_group;
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 8bfbc54660ab..2a1897d76c71 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -108,6 +108,8 @@ struct drm_plane_helper_funcs; struct drm_crtc_state { struct drm_crtc *crtc;
- unsigned int seqno;
- bool enable; bool active;
@@ -750,6 +752,8 @@ struct drm_crtc {
char *name;
- unsigned int state_seqno;
- /**
- @mutex:
@@ -816,6 +820,13 @@ struct drm_crtc { struct drm_crtc_state *state;
/**
* @committed_state:
*
* Current committed atomic state for this CRTC.
*/
- struct drm_crtc_state *committed_state;
- /**
- @commit_list:
- List of &drm_crtc_commit structures tracking pending commits.
diff --git a/include/drm/drm_plane.h b/include/drm/drm_plane.h index 08ad4b58adbe..ff3495705e63 100644 --- a/include/drm/drm_plane.h +++ b/include/drm/drm_plane.h @@ -59,6 +59,8 @@ struct drm_modeset_acquire_ctx; struct drm_plane_state { struct drm_plane *plane;
- unsigned int seqno;
- /**
- @crtc:
@@ -470,6 +472,8 @@ struct drm_plane {
char *name;
- unsigned int state_seqno;
- /**
- @mutex:
@@ -522,6 +526,13 @@ struct drm_plane { */ struct drm_plane_state *state;
- /**
* @committed_state:
*
* Current committed atomic state for this plane.
*/
- struct drm_plane_state *committed_state;
- struct drm_property *zpos_property; struct drm_property *rotation_property;
};
2.13.0
Intel-gfx mailing list Intel-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/intel-gfx
-- Daniel Vetter Software Engineer, Intel Corporation http://blog.ffwll.ch
On Fri, Jul 7, 2017 at 3:21 PM, Ville Syrjälä ville.syrjala@linux.intel.com wrote:
On Fri, Jul 07, 2017 at 02:03:38PM +0200, Daniel Vetter wrote:
On Thu, Jul 06, 2017 at 11:24:41PM +0300, ville.syrjala@linux.intel.com wrote:
From: Ville Syrjälä ville.syrjala@linux.intel.com
For i915 GPU reset handling we'll want to be able to duplicate the state that was last commited to the hardware. For that purpose let's start to track the commited state for each object and provide a way to duplicate the commmited state into a new drm_atomic_state. The locking for .commited_state must to be provided by the driver.
drm_atomic_helper_duplicate_commited_state() duplicates the state to both old_state and new_state. For the purposes of i915 GPU reset we would only need one of them, but we actually need two top level states; one for disabling everything (which would need the duplicated state to be old_state), and another to reenable everything (which would need the duplicated state to be new_state). So to make it less comples I figured I'd just always duplicate both. Might want to rethink this if for no other reason that reducing the chances of memory allocation failure. Due to the double state duplication we need drm_atomic_helper_clean_commited_state() to clean up the duplicated old_state since that's not handled by the normal drm_atomic_state cleanup code.
TODO: do we want this in the helper, or maybe it should be just in i915?
v2: s/commited/committed/ everywhere (checkpatch) Handle state duplication errors better v3: Even more care in dealing with memory allocation errors Handle private objs too Deal with the potential ordering issues between swap_state() and hw_done() by keeping track of which state was swapped in last
Signed-off-by: Ville Syrjälä ville.syrjala@linux.intel.com
I still don't get why we need to duplicate the committed state for gpu reset. When I said I'm not against adding all that complexity long-term I meant when we actually really need it. Imo g4x gpu reset isn't a good justification for that, reworking the atomic world for that seems massively out of proportion.
Well, I still don't see what's so "massive" about a couple of extra state pointers hanging around.
Also while doing that state duplication stuff, my old idea of splitting the crtc disable and enable phases into separate atomic commits popped up again in my head. For that being able to duplicate arbitrary states would seem like a nice thing to have. So the refactoring I had to do can have other uses.
I fully realize that you're unhappy with how atomic ended up getting merged and that you think it's a grave mistake. And maybe it is, maybe it isn't, I have no idea. But right now we have _nothing_ asking for that reorg afaik, and using gen4 reset to justify it is in my opinion simply not solid engineering practice. Maybe we need this in the future, and then we can add it, but not before. Refactoring stuff to prettify the architecture isn't really useful work.
Why exactly can't we do this simpler? I still don't get that part. Is there really no solution that doesn't break atomic's current assumption that commits are fully ordered on a given crtc?
From the point of view of the old and new states it doesn't actually break that. The commits done from the reset path are essentially invisible to the normal modeset operation.
You insert something into a fully ordered queue. That does break the entire concept and needs a pile of locks and stuff to make it work. Yes it's doable, but it's a redesign with all the implications of subtle breakage all over. While we do have open bugs for the current design. Rewriting the world to fix a bug needs seriously better justification imo.
The one alternative proposed idea of allowing gem and kms sides go out of whack scares me a bit. I think that might land us in more trouble when I finally get around to making the video overlay a drm_plane.
We've run perfectly fine with this idea for years.
And I think trying to keep the GPU reset paths as similar as possible between all the platforms would be a nice thing. Just whacking everything on the head with a hammer on one platform but not on another one seems to me like extra variation in behaviour that we don't necessarily want.
But like I said, if someone can come up with a better solution I probably wouldn't object too much. It's not going to be coming from me though since I have plenty of other things to do and vacation time is coming up very soon. So unless someone else comes up with something nice soon I think we should just go with my solution because a) it's already available, and b) works quite decently from what I can see.
I guess I'll have to retype the old thing in the new world, but it really shouldn't be more than the quick draft I've laid down in the old thread. This here is imo no-go with all the core changes, and even just done within i915 I think it's highly dubious that it provides a real benefit, since defacto it means we'll have to abandon the atomic helpers entirely. -Daniel
-Daniel
drivers/gpu/drm/drm_atomic.c | 1 + drivers/gpu/drm/drm_atomic_helper.c | 231 ++++++++++++++++++++++++++++++++++++ include/drm/drm_atomic.h | 4 + include/drm/drm_atomic_helper.h | 8 ++ include/drm/drm_connector.h | 11 ++ include/drm/drm_crtc.h | 11 ++ include/drm/drm_plane.h | 11 ++ 7 files changed, 277 insertions(+)
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 56925b93f598..e1578d50d66f 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -1020,6 +1020,7 @@ drm_atomic_private_obj_init(struct drm_private_obj *obj, memset(obj, 0, sizeof(*obj));
obj->state = state;
- obj->committed_state = state; obj->funcs = funcs;
} EXPORT_SYMBOL(drm_atomic_private_obj_init); diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index f0887f231fb8..c3d02f12cd5d 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -1815,6 +1815,11 @@ void drm_atomic_helper_wait_for_dependencies(struct drm_atomic_state *old_state) } EXPORT_SYMBOL(drm_atomic_helper_wait_for_dependencies);
+static bool state_seqno_after(unsigned int a, unsigned int b) +{
- return (int)(b - a) < 0;
+}
/**
- drm_atomic_helper_commit_hw_done - setup possible nonblocking commit
- @old_state: atomic state object with old state structures
@@ -1833,11 +1838,39 @@ EXPORT_SYMBOL(drm_atomic_helper_wait_for_dependencies); void drm_atomic_helper_commit_hw_done(struct drm_atomic_state *old_state) { struct drm_crtc *crtc;
struct drm_plane *plane;
struct drm_connector *connector;
struct drm_private_obj *obj; struct drm_crtc_state *new_crtc_state;
struct drm_plane_state *new_plane_state;
struct drm_connector_state *new_connector_state;
struct drm_private_state *new_obj_state; struct drm_crtc_commit *commit; int i;
static DEFINE_SPINLOCK(committed_state_lock);
spin_lock(&committed_state_lock);
for_each_new_plane_in_state(old_state, plane, new_plane_state, i) {
if (plane->committed_state &&
state_seqno_after(new_plane_state->seqno,
plane->committed_state->seqno))
plane->committed_state = new_plane_state;
}
for_each_new_connector_in_state(old_state, connector, new_connector_state, i) {
if (connector->committed_state &&
state_seqno_after(new_connector_state->seqno,
connector->committed_state->seqno))
connector->committed_state = new_connector_state;
}
for_each_new_crtc_in_state(old_state, crtc, new_crtc_state, i) {
if (crtc->committed_state &&
state_seqno_after(new_crtc_state->seqno,
crtc->committed_state->seqno))
crtc->committed_state = new_crtc_state;
commit = old_state->crtcs[i].commit; if (!commit) continue;
@@ -1846,6 +1879,15 @@ void drm_atomic_helper_commit_hw_done(struct drm_atomic_state *old_state) WARN_ON(new_crtc_state->event); complete_all(&commit->hw_done); }
- for_each_new_private_obj_in_state(old_state, obj, new_obj_state, i) {
if (obj->committed_state &&
state_seqno_after(new_obj_state->seqno,
obj->committed_state->seqno))
obj->committed_state = new_obj_state;
- }
- spin_unlock(&committed_state_lock);
} EXPORT_SYMBOL(drm_atomic_helper_commit_hw_done);
@@ -2296,6 +2338,7 @@ void drm_atomic_helper_swap_state(struct drm_atomic_state *state,
old_conn_state->state = state; new_conn_state->state = NULL;
new_conn_state->seqno = ++connector->state_seqno; __drm_atomic_state_connector(state, i)->state = old_conn_state; connector->state = new_conn_state;
@@ -2309,6 +2352,7 @@ void drm_atomic_helper_swap_state(struct drm_atomic_state *state,
state->crtcs[i].state = old_crtc_state; crtc->state = new_crtc_state;
new_crtc_state->seqno = ++crtc->state_seqno; if (state->crtcs[i].commit) { spin_lock(&crtc->commit_lock);
@@ -2325,6 +2369,7 @@ void drm_atomic_helper_swap_state(struct drm_atomic_state *state,
old_plane_state->state = state; new_plane_state->state = NULL;
new_plane_state->seqno = ++plane->state_seqno; state->planes[i].state = old_plane_state; plane->state = new_plane_state;
@@ -2335,6 +2380,7 @@ void drm_atomic_helper_swap_state(struct drm_atomic_state *state,
old_obj_state->state = state; new_obj_state->state = NULL;
new_obj_state->seqno = ++obj->state_seqno; __drm_atomic_state_private_obj(state, i)->state = old_obj_state; obj->state = new_obj_state;
@@ -3582,6 +3628,7 @@ __drm_atomic_helper_connector_reset(struct drm_connector *connector, conn_state->connector = connector;
connector->state = conn_state;
- connector->committed_state = conn_state;
} EXPORT_SYMBOL(__drm_atomic_helper_connector_reset);
@@ -3740,6 +3787,189 @@ drm_atomic_helper_duplicate_state(struct drm_device *dev, } EXPORT_SYMBOL(drm_atomic_helper_duplicate_state);
+struct drm_atomic_state * +drm_atomic_helper_duplicate_committed_state(struct drm_device *dev) +{
- struct drm_atomic_state *state;
- struct drm_connector_list_iter conn_iter;
- struct drm_connector *conn;
- struct drm_plane *plane;
- struct drm_crtc *crtc;
- int err = 0;
- state = drm_atomic_state_alloc(dev);
- if (!state)
return ERR_PTR(-ENOMEM);
- drm_for_each_plane(plane, dev) {
struct drm_plane_state *old_state, *new_state;
int i = drm_plane_index(plane);
old_state = plane->funcs->atomic_duplicate_state(plane, plane->committed_state);
if (!old_state) {
err = -ENOMEM;
goto free;
}
new_state = plane->funcs->atomic_duplicate_state(plane, plane->committed_state);
if (!new_state) {
plane->funcs->atomic_destroy_state(plane, old_state);
err = -ENOMEM;
goto free;
}
state->planes[i].state = new_state;
state->planes[i].old_state = old_state;
state->planes[i].new_state = new_state;
state->planes[i].ptr = plane;
old_state->state = state;
- }
- drm_for_each_crtc(crtc, dev) {
struct drm_crtc_state *old_state, *new_state;
int i = drm_crtc_index(crtc);
old_state = crtc->funcs->atomic_duplicate_state(crtc, crtc->committed_state);
if (!old_state) {
err = -ENOMEM;
goto free;
}
new_state = crtc->funcs->atomic_duplicate_state(crtc, crtc->committed_state);
if (!new_state) {
crtc->funcs->atomic_destroy_state(crtc, old_state);
err = -ENOMEM;
goto free;
}
state->crtcs[i].state = new_state;
state->crtcs[i].old_state = old_state;
state->crtcs[i].new_state = new_state;
state->crtcs[i].ptr = crtc;
old_state->state = state;
- }
- drm_connector_list_iter_begin(dev, &conn_iter);
- drm_for_each_connector_iter(conn, &conn_iter) {
struct drm_connector_state *old_state, *new_state;
struct __drm_connectors_state *c;
int i = drm_connector_index(conn);
err = drm_dynarray_reserve(&state->connectors, i);
if (err)
break;
old_state = conn->funcs->atomic_duplicate_state(conn, conn->committed_state);
if (!old_state) {
err = -ENOMEM;
break;
}
new_state = conn->funcs->atomic_duplicate_state(conn, conn->committed_state);
if (!new_state) {
conn->funcs->atomic_destroy_state(conn, old_state);
err = -ENOMEM;
break;
}
state->num_connector = state->connectors.num_elems;
c = __drm_atomic_state_connector(state, i);
c->state = new_state;
c->old_state = old_state;
c->new_state = new_state;
c->ptr = drm_connector_get(conn);
old_state->state = state;
- }
- drm_connector_list_iter_end(&conn_iter);
+free:
- if (err < 0) {
drm_atomic_helper_clean_committed_state(state);
drm_atomic_state_put(state);
state = ERR_PTR(err);
- }
- return state;
+} +EXPORT_SYMBOL(drm_atomic_helper_duplicate_committed_state);
+int drm_atomic_helper_duplicate_private_obj_committed_state(struct drm_atomic_state *state,
struct drm_private_obj *obj)
+{
- struct drm_private_state *old_state, *new_state;
- struct __drm_private_objs_state *p;
- int ret, i = state->num_private_objs;
- ret = drm_dynarray_reserve(&state->private_objs, i);
- if (ret)
return ret;
- old_state = obj->funcs->atomic_duplicate_state(obj, obj->committed_state);
- if (!old_state)
return -ENOMEM;
- new_state = obj->funcs->atomic_duplicate_state(obj, obj->committed_state);
- if (!new_state) {
obj->funcs->atomic_destroy_state(obj, obj->committed_state);
return -ENOMEM;
- }
- state->num_private_objs = state->private_objs.num_elems;
- p = __drm_atomic_state_private_obj(state, i);
- p->state = new_state;
- p->old_state = old_state;
- p->new_state = new_state;
- p->ptr = obj;
- old_state->state = state;
- return 0;
+} +EXPORT_SYMBOL(drm_atomic_helper_duplicate_private_obj_committed_state);
+void +drm_atomic_helper_clean_committed_state(struct drm_atomic_state *state) +{
- struct drm_plane *plane;
- struct drm_crtc *crtc;
- struct drm_connector *conn;
- struct drm_plane_state *plane_state;
- struct drm_crtc_state *crtc_state;
- struct drm_connector_state *conn_state;
- struct drm_private_obj *obj;
- struct drm_private_state *obj_state;
- int i;
- /* restore the correct state->state */
- for_each_new_plane_in_state(state, plane, plane_state, i) {
plane->funcs->atomic_destroy_state(plane, state->planes[i].old_state);
state->planes[i].old_state = NULL;
- }
- for_each_new_crtc_in_state(state, crtc, crtc_state, i) {
crtc->funcs->atomic_destroy_state(crtc, state->crtcs[i].old_state);
state->crtcs[i].old_state = NULL;
- }
- for_each_new_connector_in_state(state, conn, conn_state, i) {
struct __drm_connectors_state *c =
__drm_atomic_state_connector(state, i);
conn->funcs->atomic_destroy_state(conn, c->old_state);
c->old_state = NULL;
- }
- for_each_new_private_obj_in_state(state, obj, obj_state, i) {
struct __drm_private_objs_state *p =
__drm_atomic_state_private_obj(state, i);
obj->funcs->atomic_destroy_state(obj, p->old_state);
p->old_state = NULL;
- }
+} +EXPORT_SYMBOL(drm_atomic_helper_clean_committed_state);
/**
- __drm_atomic_helper_connector_destroy_state - release connector state
- @state: connector state object to release
@@ -3856,6 +4086,7 @@ EXPORT_SYMBOL(drm_atomic_helper_legacy_gamma_set);
- __drm_atomic_helper_private_duplicate_state - copy atomic private state
- @obj: CRTC object
- @state: new private object state
- @old_state: old private object state
- Copies atomic state from a private objects's current state and resets inferred values.
- This is useful for drivers that subclass the private state.
diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h index 0e6c54b3e0af..9ff4fb46d500 100644 --- a/include/drm/drm_atomic.h +++ b/include/drm/drm_atomic.h @@ -194,12 +194,16 @@ struct drm_private_state_funcs {
struct drm_private_obj { struct drm_private_state *state;
struct drm_private_state *committed_state;
const struct drm_private_state_funcs *funcs;
unsigned int state_seqno;
};
struct drm_private_state { struct drm_atomic_state *state;
- unsigned int seqno;
};
struct __drm_private_objs_state { diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h index b799687a4b09..3a609bbb5818 100644 --- a/include/drm/drm_atomic_helper.h +++ b/include/drm/drm_atomic_helper.h @@ -185,6 +185,14 @@ drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector, struct drm_atomic_state * drm_atomic_helper_duplicate_state(struct drm_device *dev, struct drm_modeset_acquire_ctx *ctx); +struct drm_atomic_state * +drm_atomic_helper_duplicate_committed_state(struct drm_device *dev); +struct drm_private_obj; +int +drm_atomic_helper_duplicate_private_obj_committed_state(struct drm_atomic_state *state,
struct drm_private_obj *obj);
+void +drm_atomic_helper_clean_committed_state(struct drm_atomic_state *state); void __drm_atomic_helper_connector_destroy_state(struct drm_connector_state *state); void drm_atomic_helper_connector_destroy_state(struct drm_connector *connector, diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index 8f26166f78b4..a38ba05db4fa 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -306,6 +306,8 @@ struct drm_tv_connector_state { struct drm_connector_state { struct drm_connector *connector;
- unsigned int seqno;
- /**
- @crtc: CRTC to connect connector to, NULL if disabled.
@@ -707,6 +709,8 @@ struct drm_connector {
char *name;
- unsigned int state_seqno;
- /**
- @mutex: Lock for general connector state, but currently only protects
- @registered. Most of the connector state is still protected by
@@ -868,6 +872,13 @@ struct drm_connector { */ struct drm_connector_state *state;
- /**
- @committed_state:
- Current committed atomic state for this connector.
- */
- struct drm_connector_state *committed_state;
- /* DisplayID bits */ bool has_tile; struct drm_tile_group *tile_group;
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 8bfbc54660ab..2a1897d76c71 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -108,6 +108,8 @@ struct drm_plane_helper_funcs; struct drm_crtc_state { struct drm_crtc *crtc;
- unsigned int seqno;
- bool enable; bool active;
@@ -750,6 +752,8 @@ struct drm_crtc {
char *name;
- unsigned int state_seqno;
- /**
- @mutex:
@@ -816,6 +820,13 @@ struct drm_crtc { struct drm_crtc_state *state;
/**
- @committed_state:
- Current committed atomic state for this CRTC.
- */
- struct drm_crtc_state *committed_state;
- /**
- @commit_list:
- List of &drm_crtc_commit structures tracking pending commits.
diff --git a/include/drm/drm_plane.h b/include/drm/drm_plane.h index 08ad4b58adbe..ff3495705e63 100644 --- a/include/drm/drm_plane.h +++ b/include/drm/drm_plane.h @@ -59,6 +59,8 @@ struct drm_modeset_acquire_ctx; struct drm_plane_state { struct drm_plane *plane;
- unsigned int seqno;
- /**
- @crtc:
@@ -470,6 +472,8 @@ struct drm_plane {
char *name;
- unsigned int state_seqno;
- /**
- @mutex:
@@ -522,6 +526,13 @@ struct drm_plane { */ struct drm_plane_state *state;
- /**
- @committed_state:
- Current committed atomic state for this plane.
- */
- struct drm_plane_state *committed_state;
- struct drm_property *zpos_property; struct drm_property *rotation_property;
};
2.13.0
Intel-gfx mailing list Intel-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/intel-gfx
-- Daniel Vetter Software Engineer, Intel Corporation http://blog.ffwll.ch
-- Ville Syrjälä Intel OTC
On Fri, Jul 07, 2017 at 04:05:28PM +0200, Daniel Vetter wrote:
On Fri, Jul 7, 2017 at 3:21 PM, Ville Syrjälä ville.syrjala@linux.intel.com wrote:
On Fri, Jul 07, 2017 at 02:03:38PM +0200, Daniel Vetter wrote:
On Thu, Jul 06, 2017 at 11:24:41PM +0300, ville.syrjala@linux.intel.com wrote:
From: Ville Syrjälä ville.syrjala@linux.intel.com
For i915 GPU reset handling we'll want to be able to duplicate the state that was last commited to the hardware. For that purpose let's start to track the commited state for each object and provide a way to duplicate the commmited state into a new drm_atomic_state. The locking for .commited_state must to be provided by the driver.
drm_atomic_helper_duplicate_commited_state() duplicates the state to both old_state and new_state. For the purposes of i915 GPU reset we would only need one of them, but we actually need two top level states; one for disabling everything (which would need the duplicated state to be old_state), and another to reenable everything (which would need the duplicated state to be new_state). So to make it less comples I figured I'd just always duplicate both. Might want to rethink this if for no other reason that reducing the chances of memory allocation failure. Due to the double state duplication we need drm_atomic_helper_clean_commited_state() to clean up the duplicated old_state since that's not handled by the normal drm_atomic_state cleanup code.
TODO: do we want this in the helper, or maybe it should be just in i915?
v2: s/commited/committed/ everywhere (checkpatch) Handle state duplication errors better v3: Even more care in dealing with memory allocation errors Handle private objs too Deal with the potential ordering issues between swap_state() and hw_done() by keeping track of which state was swapped in last
Signed-off-by: Ville Syrjälä ville.syrjala@linux.intel.com
I still don't get why we need to duplicate the committed state for gpu reset. When I said I'm not against adding all that complexity long-term I meant when we actually really need it. Imo g4x gpu reset isn't a good justification for that, reworking the atomic world for that seems massively out of proportion.
Well, I still don't see what's so "massive" about a couple of extra state pointers hanging around.
Also while doing that state duplication stuff, my old idea of splitting the crtc disable and enable phases into separate atomic commits popped up again in my head. For that being able to duplicate arbitrary states would seem like a nice thing to have. So the refactoring I had to do can have other uses.
I fully realize that you're unhappy with how atomic ended up getting merged and that you think it's a grave mistake. And maybe it is, maybe it isn't, I have no idea.
I don't think I ever said that. I've said that it has certain design problems that we ought to fix. This one being one, and another being to separate the user state from the internal state. The latter I think we'll have to tackle rather soon thanks to some new hardware in the pipeline, or we need to come up with some other way to achieve the same effect.
But right now we have _nothing_ asking for that reorg afaik, and using gen4 reset to justify it is in my opinion simply not solid engineering practice. Maybe we need this in the future, and then we can add it, but not before. Refactoring stuff to prettify the architecture isn't really useful work.
Neither is having to throw out code that already exists and works. If you're so worried about time being wasted on pre-g4x GPU reset, then we could just as well merge my code and move on to more productive endeavors.
Why exactly can't we do this simpler? I still don't get that part. Is there really no solution that doesn't break atomic's current assumption that commits are fully ordered on a given crtc?
From the point of view of the old and new states it doesn't actually break that. The commits done from the reset path are essentially invisible to the normal modeset operation.
You insert something into a fully ordered queue. That does break the entire concept and needs a pile of locks and stuff to make it work.
Exactly one lock. Well two if you could the spinlock to protect the committed_state pointer update from parallel updates touching the same kms object. That latter one could be removed if atomic wouldn't allow parallel commits to touch the same object.
Yes it's doable, but it's a redesign with all the implications of subtle breakage all over.
What? It doesn't really even do anything unless you do the duplicate_committed state(). Everything else is just assigning pointers. So unless there's some really obvious bug somewhere it can't break anything outside the GPU reset path. And really the only way to break to GPU reset path is to have actual bugs in the normal display commit code.
While we do have open bugs for the current design. Rewriting the world to fix a bug needs seriously better justification imo.
The one alternative proposed idea of allowing gem and kms sides go out of whack scares me a bit. I think that might land us in more trouble when I finally get around to making the video overlay a drm_plane.
We've run perfectly fine with this idea for years.
Not perfectly. I've had to fix it several times. And I don't think I was the only one.
And I think trying to keep the GPU reset paths as similar as possible between all the platforms would be a nice thing. Just whacking everything on the head with a hammer on one platform but not on another one seems to me like extra variation in behaviour that we don't necessarily want.
But like I said, if someone can come up with a better solution I probably wouldn't object too much. It's not going to be coming from me though since I have plenty of other things to do and vacation time is coming up very soon. So unless someone else comes up with something nice soon I think we should just go with my solution because a) it's already available, and b) works quite decently from what I can see.
I guess I'll have to retype the old thing in the new world, but it really shouldn't be more than the quick draft I've laid down in the old thread. This here is imo no-go with all the core changes, and even just done within i915 I think it's highly dubious that it provides a real benefit, since defacto it means we'll have to abandon the atomic helpers entirely.
Now I think you're just being difficult for the sake of it. Have you looked at the code at all? It's fully done from the atomic helpers right now. And even moving the committed state tracking to i915 wouldn't require abandoning the helpers. We could just update the committed state pointers when we call hw_done(), and we'd have to update the state seqno/age timestamp when we call swap_state(). That's all there is to this.
On Fri, Jul 07, 2017 at 06:18:12PM +0300, Ville Syrjälä wrote:
On Fri, Jul 07, 2017 at 04:05:28PM +0200, Daniel Vetter wrote:
On Fri, Jul 7, 2017 at 3:21 PM, Ville Syrjälä ville.syrjala@linux.intel.com wrote:
On Fri, Jul 07, 2017 at 02:03:38PM +0200, Daniel Vetter wrote:
On Thu, Jul 06, 2017 at 11:24:41PM +0300, ville.syrjala@linux.intel.com wrote:
From: Ville Syrjälä ville.syrjala@linux.intel.com
For i915 GPU reset handling we'll want to be able to duplicate the state that was last commited to the hardware. For that purpose let's start to track the commited state for each object and provide a way to duplicate the commmited state into a new drm_atomic_state. The locking for .commited_state must to be provided by the driver.
drm_atomic_helper_duplicate_commited_state() duplicates the state to both old_state and new_state. For the purposes of i915 GPU reset we would only need one of them, but we actually need two top level states; one for disabling everything (which would need the duplicated state to be old_state), and another to reenable everything (which would need the duplicated state to be new_state). So to make it less comples I figured I'd just always duplicate both. Might want to rethink this if for no other reason that reducing the chances of memory allocation failure. Due to the double state duplication we need drm_atomic_helper_clean_commited_state() to clean up the duplicated old_state since that's not handled by the normal drm_atomic_state cleanup code.
TODO: do we want this in the helper, or maybe it should be just in i915?
v2: s/commited/committed/ everywhere (checkpatch) Handle state duplication errors better v3: Even more care in dealing with memory allocation errors Handle private objs too Deal with the potential ordering issues between swap_state() and hw_done() by keeping track of which state was swapped in last
Signed-off-by: Ville Syrjälä ville.syrjala@linux.intel.com
I still don't get why we need to duplicate the committed state for gpu reset. When I said I'm not against adding all that complexity long-term I meant when we actually really need it. Imo g4x gpu reset isn't a good justification for that, reworking the atomic world for that seems massively out of proportion.
Well, I still don't see what's so "massive" about a couple of extra state pointers hanging around.
Also while doing that state duplication stuff, my old idea of splitting the crtc disable and enable phases into separate atomic commits popped up again in my head. For that being able to duplicate arbitrary states would seem like a nice thing to have. So the refactoring I had to do can have other uses.
I fully realize that you're unhappy with how atomic ended up getting merged and that you think it's a grave mistake. And maybe it is, maybe it isn't, I have no idea.
I don't think I ever said that. I've said that it has certain design problems that we ought to fix. This one being one, and another being to separate the user state from the internal state. The latter I think we'll have to tackle rather soon thanks to some new hardware in the pipeline, or we need to come up with some other way to achieve the same effect.
But right now we have _nothing_ asking for that reorg afaik, and using gen4 reset to justify it is in my opinion simply not solid engineering practice. Maybe we need this in the future, and then we can add it, but not before. Refactoring stuff to prettify the architecture isn't really useful work.
Neither is having to throw out code that already exists and works. If you're so worried about time being wasted on pre-g4x GPU reset, then we could just as well merge my code and move on to more productive endeavors.
I'm worried about future time wasted on this, not current time.
Why exactly can't we do this simpler? I still don't get that part. Is there really no solution that doesn't break atomic's current assumption that commits are fully ordered on a given crtc?
From the point of view of the old and new states it doesn't actually break that. The commits done from the reset path are essentially invisible to the normal modeset operation.
You insert something into a fully ordered queue. That does break the entire concept and needs a pile of locks and stuff to make it work.
Exactly one lock. Well two if you could the spinlock to protect the committed_state pointer update from parallel updates touching the same kms object. That latter one could be removed if atomic wouldn't allow parallel commits to touch the same object.
Yes it's doable, but it's a redesign with all the implications of subtle breakage all over.
What? It doesn't really even do anything unless you do the duplicate_committed state(). Everything else is just assigning pointers. So unless there's some really obvious bug somewhere it can't break anything outside the GPU reset path. And really the only way to break to GPU reset path is to have actual bugs in the normal display commit code.
It's the gpu reset I'm worried about. There's no point in fixing it if it immediately breaks again.
While we do have open bugs for the current design. Rewriting the world to fix a bug needs seriously better justification imo.
The one alternative proposed idea of allowing gem and kms sides go out of whack scares me a bit. I think that might land us in more trouble when I finally get around to making the video overlay a drm_plane.
We've run perfectly fine with this idea for years.
Not perfectly. I've had to fix it several times. And I don't think I was the only one.
The problem is that no one tests against gen4, and everyone forgets that it exists. That's why I'd like something with the minimal amount of invasiveness, since that would at least be easier to patch up when we inevitably break it. Also, something entirely contained to i915 conceptually, without imposing more restrictions on shared code.
And I think trying to keep the GPU reset paths as similar as possible between all the platforms would be a nice thing. Just whacking everything on the head with a hammer on one platform but not on another one seems to me like extra variation in behaviour that we don't necessarily want.
But like I said, if someone can come up with a better solution I probably wouldn't object too much. It's not going to be coming from me though since I have plenty of other things to do and vacation time is coming up very soon. So unless someone else comes up with something nice soon I think we should just go with my solution because a) it's already available, and b) works quite decently from what I can see.
I guess I'll have to retype the old thing in the new world, but it really shouldn't be more than the quick draft I've laid down in the old thread. This here is imo no-go with all the core changes, and even just done within i915 I think it's highly dubious that it provides a real benefit, since defacto it means we'll have to abandon the atomic helpers entirely.
Now I think you're just being difficult for the sake of it. Have you looked at the code at all? It's fully done from the atomic helpers right now. And even moving the committed state tracking to i915 wouldn't require abandoning the helpers. We could just update the committed state pointers when we call hw_done(), and we'd have to update the state seqno/age timestamp when we call swap_state(). That's all there is to this.
I'm concerned with the maintainenace burden you impose on all future i915 atomic work, that's all. Yes it looks simple to you and right now, but it's another little thing to keep working, and we're really good at breaking stuff all the time.
But if you strongly think this is the best possible approach overall, taking into account long-term impact, then go ahead with implementing this in i915. Adding it the concept of a committed state and being able to duplicate that and squeeze another commit in to the shared atomic helpers doesn't make sense imo. -Daniel
Op 10-07-17 om 08:43 schreef Daniel Vetter:
On Fri, Jul 07, 2017 at 06:18:12PM +0300, Ville Syrjälä wrote:
On Fri, Jul 07, 2017 at 04:05:28PM +0200, Daniel Vetter wrote:
On Fri, Jul 7, 2017 at 3:21 PM, Ville Syrjälä ville.syrjala@linux.intel.com wrote:
On Fri, Jul 07, 2017 at 02:03:38PM +0200, Daniel Vetter wrote:
On Thu, Jul 06, 2017 at 11:24:41PM +0300, ville.syrjala@linux.intel.com wrote:
From: Ville Syrjälä ville.syrjala@linux.intel.com
For i915 GPU reset handling we'll want to be able to duplicate the state that was last commited to the hardware. For that purpose let's start to track the commited state for each object and provide a way to duplicate the commmited state into a new drm_atomic_state. The locking for .commited_state must to be provided by the driver.
drm_atomic_helper_duplicate_commited_state() duplicates the state to both old_state and new_state. For the purposes of i915 GPU reset we would only need one of them, but we actually need two top level states; one for disabling everything (which would need the duplicated state to be old_state), and another to reenable everything (which would need the duplicated state to be new_state). So to make it less comples I figured I'd just always duplicate both. Might want to rethink this if for no other reason that reducing the chances of memory allocation failure. Due to the double state duplication we need drm_atomic_helper_clean_commited_state() to clean up the duplicated old_state since that's not handled by the normal drm_atomic_state cleanup code.
TODO: do we want this in the helper, or maybe it should be just in i915?
v2: s/commited/committed/ everywhere (checkpatch) Handle state duplication errors better v3: Even more care in dealing with memory allocation errors Handle private objs too Deal with the potential ordering issues between swap_state() and hw_done() by keeping track of which state was swapped in last
Signed-off-by: Ville Syrjälä ville.syrjala@linux.intel.com
I still don't get why we need to duplicate the committed state for gpu reset. When I said I'm not against adding all that complexity long-term I meant when we actually really need it. Imo g4x gpu reset isn't a good justification for that, reworking the atomic world for that seems massively out of proportion.
Well, I still don't see what's so "massive" about a couple of extra state pointers hanging around.
Also while doing that state duplication stuff, my old idea of splitting the crtc disable and enable phases into separate atomic commits popped up again in my head. For that being able to duplicate arbitrary states would seem like a nice thing to have. So the refactoring I had to do can have other uses.
I fully realize that you're unhappy with how atomic ended up getting merged and that you think it's a grave mistake. And maybe it is, maybe it isn't, I have no idea.
I don't think I ever said that. I've said that it has certain design problems that we ought to fix. This one being one, and another being to separate the user state from the internal state. The latter I think we'll have to tackle rather soon thanks to some new hardware in the pipeline, or we need to come up with some other way to achieve the same effect.
But right now we have _nothing_ asking for that reorg afaik, and using gen4 reset to justify it is in my opinion simply not solid engineering practice. Maybe we need this in the future, and then we can add it, but not before. Refactoring stuff to prettify the architecture isn't really useful work.
Neither is having to throw out code that already exists and works. If you're so worried about time being wasted on pre-g4x GPU reset, then we could just as well merge my code and move on to more productive endeavors.
I'm worried about future time wasted on this, not current time.
Why exactly can't we do this simpler? I still don't get that part. Is there really no solution that doesn't break atomic's current assumption that commits are fully ordered on a given crtc?
From the point of view of the old and new states it doesn't actually break that. The commits done from the reset path are essentially invisible to the normal modeset operation.
You insert something into a fully ordered queue. That does break the entire concept and needs a pile of locks and stuff to make it work.
Exactly one lock. Well two if you could the spinlock to protect the committed_state pointer update from parallel updates touching the same kms object. That latter one could be removed if atomic wouldn't allow parallel commits to touch the same object.
Yes it's doable, but it's a redesign with all the implications of subtle breakage all over.
What? It doesn't really even do anything unless you do the duplicate_committed state(). Everything else is just assigning pointers. So unless there's some really obvious bug somewhere it can't break anything outside the GPU reset path. And really the only way to break to GPU reset path is to have actual bugs in the normal display commit code.
It's the gpu reset I'm worried about. There's no point in fixing it if it immediately breaks again.
While we do have open bugs for the current design. Rewriting the world to fix a bug needs seriously better justification imo.
The one alternative proposed idea of allowing gem and kms sides go out of whack scares me a bit. I think that might land us in more trouble when I finally get around to making the video overlay a drm_plane.
We've run perfectly fine with this idea for years.
Not perfectly. I've had to fix it several times. And I don't think I was the only one.
The problem is that no one tests against gen4, and everyone forgets that it exists. That's why I'd like something with the minimal amount of invasiveness, since that would at least be easier to patch up when we inevitably break it. Also, something entirely contained to i915 conceptually, without imposing more restrictions on shared code.
And I think trying to keep the GPU reset paths as similar as possible between all the platforms would be a nice thing. Just whacking everything on the head with a hammer on one platform but not on another one seems to me like extra variation in behaviour that we don't necessarily want.
But like I said, if someone can come up with a better solution I probably wouldn't object too much. It's not going to be coming from me though since I have plenty of other things to do and vacation time is coming up very soon. So unless someone else comes up with something nice soon I think we should just go with my solution because a) it's already available, and b) works quite decently from what I can see.
I guess I'll have to retype the old thing in the new world, but it really shouldn't be more than the quick draft I've laid down in the old thread. This here is imo no-go with all the core changes, and even just done within i915 I think it's highly dubious that it provides a real benefit, since defacto it means we'll have to abandon the atomic helpers entirely.
Now I think you're just being difficult for the sake of it. Have you looked at the code at all? It's fully done from the atomic helpers right now. And even moving the committed state tracking to i915 wouldn't require abandoning the helpers. We could just update the committed state pointers when we call hw_done(), and we'd have to update the state seqno/age timestamp when we call swap_state(). That's all there is to this.
I'm concerned with the maintainenace burden you impose on all future i915 atomic work, that's all. Yes it looks simple to you and right now, but it's another little thing to keep working, and we're really good at breaking stuff all the time.
But if you strongly think this is the best possible approach overall, taking into account long-term impact, then go ahead with implementing this in i915. Adding it the concept of a committed state and being able to duplicate that and squeeze another commit in to the shared atomic helpers doesn't make sense imo. -Daniel
I think the problem is about struct_mutex usage by atomic commit during reset. GPU reset has to wait for all previous atomic updates to complete, but cleanup_planes and prepare_plane_fb both require struct_mutex, which can lead to a deadlock. #99093
The real fix is not taking struct_mutex during atomic commit, which will mean no deadlock can happen.
Is this the bug being fixed here or am I missing something?
~Maarten
On Mon, Jul 10, 2017 at 11:31:55AM +0200, Maarten Lankhorst wrote:
Op 10-07-17 om 08:43 schreef Daniel Vetter:
On Fri, Jul 07, 2017 at 06:18:12PM +0300, Ville Syrjälä wrote:
On Fri, Jul 07, 2017 at 04:05:28PM +0200, Daniel Vetter wrote:
On Fri, Jul 7, 2017 at 3:21 PM, Ville Syrjälä ville.syrjala@linux.intel.com wrote:
On Fri, Jul 07, 2017 at 02:03:38PM +0200, Daniel Vetter wrote:
On Thu, Jul 06, 2017 at 11:24:41PM +0300, ville.syrjala@linux.intel.com wrote: > From: Ville Syrjälä ville.syrjala@linux.intel.com > > For i915 GPU reset handling we'll want to be able to duplicate the state > that was last commited to the hardware. For that purpose let's start to > track the commited state for each object and provide a way to duplicate > the commmited state into a new drm_atomic_state. The locking for > .commited_state must to be provided by the driver. > > drm_atomic_helper_duplicate_commited_state() duplicates the state > to both old_state and new_state. For the purposes of i915 GPU reset we > would only need one of them, but we actually need two top level states; > one for disabling everything (which would need the duplicated state to > be old_state), and another to reenable everything (which would need the > duplicated state to be new_state). So to make it less comples I figured > I'd just always duplicate both. Might want to rethink this if for no > other reason that reducing the chances of memory allocation failure. > Due to the double state duplication we need > drm_atomic_helper_clean_commited_state() to clean up the duplicated > old_state since that's not handled by the normal drm_atomic_state > cleanup code. > > TODO: do we want this in the helper, or maybe it should be just in i915? > > v2: s/commited/committed/ everywhere (checkpatch) > Handle state duplication errors better > v3: Even more care in dealing with memory allocation errors > Handle private objs too > Deal with the potential ordering issues between swap_state() > and hw_done() by keeping track of which state was swapped in > last > > Signed-off-by: Ville Syrjälä ville.syrjala@linux.intel.com I still don't get why we need to duplicate the committed state for gpu reset. When I said I'm not against adding all that complexity long-term I meant when we actually really need it. Imo g4x gpu reset isn't a good justification for that, reworking the atomic world for that seems massively out of proportion.
Well, I still don't see what's so "massive" about a couple of extra state pointers hanging around.
Also while doing that state duplication stuff, my old idea of splitting the crtc disable and enable phases into separate atomic commits popped up again in my head. For that being able to duplicate arbitrary states would seem like a nice thing to have. So the refactoring I had to do can have other uses.
I fully realize that you're unhappy with how atomic ended up getting merged and that you think it's a grave mistake. And maybe it is, maybe it isn't, I have no idea.
I don't think I ever said that. I've said that it has certain design problems that we ought to fix. This one being one, and another being to separate the user state from the internal state. The latter I think we'll have to tackle rather soon thanks to some new hardware in the pipeline, or we need to come up with some other way to achieve the same effect.
But right now we have _nothing_ asking for that reorg afaik, and using gen4 reset to justify it is in my opinion simply not solid engineering practice. Maybe we need this in the future, and then we can add it, but not before. Refactoring stuff to prettify the architecture isn't really useful work.
Neither is having to throw out code that already exists and works. If you're so worried about time being wasted on pre-g4x GPU reset, then we could just as well merge my code and move on to more productive endeavors.
I'm worried about future time wasted on this, not current time.
Why exactly can't we do this simpler? I still don't get that part. Is there really no solution that doesn't break atomic's current assumption that commits are fully ordered on a given crtc?
From the point of view of the old and new states it doesn't actually break that. The commits done from the reset path are essentially invisible to the normal modeset operation.
You insert something into a fully ordered queue. That does break the entire concept and needs a pile of locks and stuff to make it work.
Exactly one lock. Well two if you could the spinlock to protect the committed_state pointer update from parallel updates touching the same kms object. That latter one could be removed if atomic wouldn't allow parallel commits to touch the same object.
Yes it's doable, but it's a redesign with all the implications of subtle breakage all over.
What? It doesn't really even do anything unless you do the duplicate_committed state(). Everything else is just assigning pointers. So unless there's some really obvious bug somewhere it can't break anything outside the GPU reset path. And really the only way to break to GPU reset path is to have actual bugs in the normal display commit code.
It's the gpu reset I'm worried about. There's no point in fixing it if it immediately breaks again.
While we do have open bugs for the current design. Rewriting the world to fix a bug needs seriously better justification imo.
The one alternative proposed idea of allowing gem and kms sides go out of whack scares me a bit. I think that might land us in more trouble when I finally get around to making the video overlay a drm_plane.
We've run perfectly fine with this idea for years.
Not perfectly. I've had to fix it several times. And I don't think I was the only one.
The problem is that no one tests against gen4, and everyone forgets that it exists. That's why I'd like something with the minimal amount of invasiveness, since that would at least be easier to patch up when we inevitably break it. Also, something entirely contained to i915 conceptually, without imposing more restrictions on shared code.
And I think trying to keep the GPU reset paths as similar as possible between all the platforms would be a nice thing. Just whacking everything on the head with a hammer on one platform but not on another one seems to me like extra variation in behaviour that we don't necessarily want.
But like I said, if someone can come up with a better solution I probably wouldn't object too much. It's not going to be coming from me though since I have plenty of other things to do and vacation time is coming up very soon. So unless someone else comes up with something nice soon I think we should just go with my solution because a) it's already available, and b) works quite decently from what I can see.
I guess I'll have to retype the old thing in the new world, but it really shouldn't be more than the quick draft I've laid down in the old thread. This here is imo no-go with all the core changes, and even just done within i915 I think it's highly dubious that it provides a real benefit, since defacto it means we'll have to abandon the atomic helpers entirely.
Now I think you're just being difficult for the sake of it. Have you looked at the code at all? It's fully done from the atomic helpers right now. And even moving the committed state tracking to i915 wouldn't require abandoning the helpers. We could just update the committed state pointers when we call hw_done(), and we'd have to update the state seqno/age timestamp when we call swap_state(). That's all there is to this.
I'm concerned with the maintainenace burden you impose on all future i915 atomic work, that's all. Yes it looks simple to you and right now, but it's another little thing to keep working, and we're really good at breaking stuff all the time.
But if you strongly think this is the best possible approach overall, taking into account long-term impact, then go ahead with implementing this in i915. Adding it the concept of a committed state and being able to duplicate that and squeeze another commit in to the shared atomic helpers doesn't make sense imo. -Daniel
I think the problem is about struct_mutex usage by atomic commit during reset. GPU reset has to wait for all previous atomic updates to complete, but cleanup_planes and prepare_plane_fb both require struct_mutex, which can lead to a deadlock. #99093
The deadlocks I've seen recently didn't necessarily involve struct_mutex IIRC. Just the modeset locks.
The real fix is not taking struct_mutex during atomic commit, which will mean no deadlock can happen.
Is this the bug being fixed here or am I missing something?
This would avoid both struct_mutex and modeset locks in the display reset path, so I guess it should help with struct_mutex issues as well.
Op 10-07-17 om 14:18 schreef Ville Syrjälä:
On Mon, Jul 10, 2017 at 11:31:55AM +0200, Maarten Lankhorst wrote:
Op 10-07-17 om 08:43 schreef Daniel Vetter:
On Fri, Jul 07, 2017 at 06:18:12PM +0300, Ville Syrjälä wrote:
On Fri, Jul 07, 2017 at 04:05:28PM +0200, Daniel Vetter wrote:
On Fri, Jul 7, 2017 at 3:21 PM, Ville Syrjälä ville.syrjala@linux.intel.com wrote:
On Fri, Jul 07, 2017 at 02:03:38PM +0200, Daniel Vetter wrote: > On Thu, Jul 06, 2017 at 11:24:41PM +0300, ville.syrjala@linux.intel.com wrote: >> From: Ville Syrjälä ville.syrjala@linux.intel.com >> >> For i915 GPU reset handling we'll want to be able to duplicate the state >> that was last commited to the hardware. For that purpose let's start to >> track the commited state for each object and provide a way to duplicate >> the commmited state into a new drm_atomic_state. The locking for >> .commited_state must to be provided by the driver. >> >> drm_atomic_helper_duplicate_commited_state() duplicates the state >> to both old_state and new_state. For the purposes of i915 GPU reset we >> would only need one of them, but we actually need two top level states; >> one for disabling everything (which would need the duplicated state to >> be old_state), and another to reenable everything (which would need the >> duplicated state to be new_state). So to make it less comples I figured >> I'd just always duplicate both. Might want to rethink this if for no >> other reason that reducing the chances of memory allocation failure. >> Due to the double state duplication we need >> drm_atomic_helper_clean_commited_state() to clean up the duplicated >> old_state since that's not handled by the normal drm_atomic_state >> cleanup code. >> >> TODO: do we want this in the helper, or maybe it should be just in i915? >> >> v2: s/commited/committed/ everywhere (checkpatch) >> Handle state duplication errors better >> v3: Even more care in dealing with memory allocation errors >> Handle private objs too >> Deal with the potential ordering issues between swap_state() >> and hw_done() by keeping track of which state was swapped in >> last >> >> Signed-off-by: Ville Syrjälä ville.syrjala@linux.intel.com > I still don't get why we need to duplicate the committed state for gpu > reset. When I said I'm not against adding all that complexity long-term I > meant when we actually really need it. Imo g4x gpu reset isn't a good > justification for that, reworking the atomic world for that seems > massively out of proportion. Well, I still don't see what's so "massive" about a couple of extra state pointers hanging around.
Also while doing that state duplication stuff, my old idea of splitting the crtc disable and enable phases into separate atomic commits popped up again in my head. For that being able to duplicate arbitrary states would seem like a nice thing to have. So the refactoring I had to do can have other uses.
I fully realize that you're unhappy with how atomic ended up getting merged and that you think it's a grave mistake. And maybe it is, maybe it isn't, I have no idea.
I don't think I ever said that. I've said that it has certain design problems that we ought to fix. This one being one, and another being to separate the user state from the internal state. The latter I think we'll have to tackle rather soon thanks to some new hardware in the pipeline, or we need to come up with some other way to achieve the same effect.
But right now we have _nothing_ asking for that reorg afaik, and using gen4 reset to justify it is in my opinion simply not solid engineering practice. Maybe we need this in the future, and then we can add it, but not before. Refactoring stuff to prettify the architecture isn't really useful work.
Neither is having to throw out code that already exists and works. If you're so worried about time being wasted on pre-g4x GPU reset, then we could just as well merge my code and move on to more productive endeavors.
I'm worried about future time wasted on this, not current time.
> Why exactly can't we do this simpler? I still don't get that part. Is > there really no solution that doesn't break atomic's current assumption > that commits are fully ordered on a given crtc? From the point of view of the old and new states it doesn't actually break that. The commits done from the reset path are essentially invisible to the normal modeset operation.
You insert something into a fully ordered queue. That does break the entire concept and needs a pile of locks and stuff to make it work.
Exactly one lock. Well two if you could the spinlock to protect the committed_state pointer update from parallel updates touching the same kms object. That latter one could be removed if atomic wouldn't allow parallel commits to touch the same object.
Yes it's doable, but it's a redesign with all the implications of subtle breakage all over.
What? It doesn't really even do anything unless you do the duplicate_committed state(). Everything else is just assigning pointers. So unless there's some really obvious bug somewhere it can't break anything outside the GPU reset path. And really the only way to break to GPU reset path is to have actual bugs in the normal display commit code.
It's the gpu reset I'm worried about. There's no point in fixing it if it immediately breaks again.
While we do have open bugs for the current design. Rewriting the world to fix a bug needs seriously better justification imo.
The one alternative proposed idea of allowing gem and kms sides go out of whack scares me a bit. I think that might land us in more trouble when I finally get around to making the video overlay a drm_plane.
We've run perfectly fine with this idea for years.
Not perfectly. I've had to fix it several times. And I don't think I was the only one.
The problem is that no one tests against gen4, and everyone forgets that it exists. That's why I'd like something with the minimal amount of invasiveness, since that would at least be easier to patch up when we inevitably break it. Also, something entirely contained to i915 conceptually, without imposing more restrictions on shared code.
And I think trying to keep the GPU reset paths as similar as possible between all the platforms would be a nice thing. Just whacking everything on the head with a hammer on one platform but not on another one seems to me like extra variation in behaviour that we don't necessarily want.
But like I said, if someone can come up with a better solution I probably wouldn't object too much. It's not going to be coming from me though since I have plenty of other things to do and vacation time is coming up very soon. So unless someone else comes up with something nice soon I think we should just go with my solution because a) it's already available, and b) works quite decently from what I can see.
I guess I'll have to retype the old thing in the new world, but it really shouldn't be more than the quick draft I've laid down in the old thread. This here is imo no-go with all the core changes, and even just done within i915 I think it's highly dubious that it provides a real benefit, since defacto it means we'll have to abandon the atomic helpers entirely.
Now I think you're just being difficult for the sake of it. Have you looked at the code at all? It's fully done from the atomic helpers right now. And even moving the committed state tracking to i915 wouldn't require abandoning the helpers. We could just update the committed state pointers when we call hw_done(), and we'd have to update the state seqno/age timestamp when we call swap_state(). That's all there is to this.
I'm concerned with the maintainenace burden you impose on all future i915 atomic work, that's all. Yes it looks simple to you and right now, but it's another little thing to keep working, and we're really good at breaking stuff all the time.
But if you strongly think this is the best possible approach overall, taking into account long-term impact, then go ahead with implementing this in i915. Adding it the concept of a committed state and being able to duplicate that and squeeze another commit in to the shared atomic helpers doesn't make sense imo. -Daniel
I think the problem is about struct_mutex usage by atomic commit during reset. GPU reset has to wait for all previous atomic updates to complete, but cleanup_planes and prepare_plane_fb both require struct_mutex, which can lead to a deadlock. #99093
The deadlocks I've seen recently didn't necessarily involve struct_mutex IIRC. Just the modeset locks.
The real fix is not taking struct_mutex during atomic commit, which will mean no deadlock can happen.
Is this the bug being fixed here or am I missing something?
This would avoid both struct_mutex and modeset locks in the display reset path, so I guess it should help with struct_mutex issues as well.
I think fixing i915 to not require struct_mutex for vma pinning/unpinning will be a better use of our time, and it should also fix all deadlocks. :)
And it's far better than duplicating drm_atomic_commit functionality in our reset handlers.
On Mon, Jul 10, 2017 at 03:26:18PM +0200, Maarten Lankhorst wrote:
Op 10-07-17 om 14:18 schreef Ville Syrjälä:
On Mon, Jul 10, 2017 at 11:31:55AM +0200, Maarten Lankhorst wrote:
Op 10-07-17 om 08:43 schreef Daniel Vetter:
On Fri, Jul 07, 2017 at 06:18:12PM +0300, Ville Syrjälä wrote:
On Fri, Jul 07, 2017 at 04:05:28PM +0200, Daniel Vetter wrote:
On Fri, Jul 7, 2017 at 3:21 PM, Ville Syrjälä ville.syrjala@linux.intel.com wrote: > On Fri, Jul 07, 2017 at 02:03:38PM +0200, Daniel Vetter wrote: >> On Thu, Jul 06, 2017 at 11:24:41PM +0300, ville.syrjala@linux.intel.com wrote: >>> From: Ville Syrjälä ville.syrjala@linux.intel.com >>> >>> For i915 GPU reset handling we'll want to be able to duplicate the state >>> that was last commited to the hardware. For that purpose let's start to >>> track the commited state for each object and provide a way to duplicate >>> the commmited state into a new drm_atomic_state. The locking for >>> .commited_state must to be provided by the driver. >>> >>> drm_atomic_helper_duplicate_commited_state() duplicates the state >>> to both old_state and new_state. For the purposes of i915 GPU reset we >>> would only need one of them, but we actually need two top level states; >>> one for disabling everything (which would need the duplicated state to >>> be old_state), and another to reenable everything (which would need the >>> duplicated state to be new_state). So to make it less comples I figured >>> I'd just always duplicate both. Might want to rethink this if for no >>> other reason that reducing the chances of memory allocation failure. >>> Due to the double state duplication we need >>> drm_atomic_helper_clean_commited_state() to clean up the duplicated >>> old_state since that's not handled by the normal drm_atomic_state >>> cleanup code. >>> >>> TODO: do we want this in the helper, or maybe it should be just in i915? >>> >>> v2: s/commited/committed/ everywhere (checkpatch) >>> Handle state duplication errors better >>> v3: Even more care in dealing with memory allocation errors >>> Handle private objs too >>> Deal with the potential ordering issues between swap_state() >>> and hw_done() by keeping track of which state was swapped in >>> last >>> >>> Signed-off-by: Ville Syrjälä ville.syrjala@linux.intel.com >> I still don't get why we need to duplicate the committed state for gpu >> reset. When I said I'm not against adding all that complexity long-term I >> meant when we actually really need it. Imo g4x gpu reset isn't a good >> justification for that, reworking the atomic world for that seems >> massively out of proportion. > Well, I still don't see what's so "massive" about a couple of extra state > pointers hanging around. > > Also while doing that state duplication stuff, my old idea of > splitting the crtc disable and enable phases into separate atomic > commits popped up again in my head. For that being able to duplicate > arbitrary states would seem like a nice thing to have. So the > refactoring I had to do can have other uses. I fully realize that you're unhappy with how atomic ended up getting merged and that you think it's a grave mistake. And maybe it is, maybe it isn't, I have no idea.
I don't think I ever said that. I've said that it has certain design problems that we ought to fix. This one being one, and another being to separate the user state from the internal state. The latter I think we'll have to tackle rather soon thanks to some new hardware in the pipeline, or we need to come up with some other way to achieve the same effect.
But right now we have _nothing_ asking for that reorg afaik, and using gen4 reset to justify it is in my opinion simply not solid engineering practice. Maybe we need this in the future, and then we can add it, but not before. Refactoring stuff to prettify the architecture isn't really useful work.
Neither is having to throw out code that already exists and works. If you're so worried about time being wasted on pre-g4x GPU reset, then we could just as well merge my code and move on to more productive endeavors.
I'm worried about future time wasted on this, not current time.
>> Why exactly can't we do this simpler? I still don't get that part. Is >> there really no solution that doesn't break atomic's current assumption >> that commits are fully ordered on a given crtc? > From the point of view of the old and new states it doesn't actually > break that. The commits done from the reset path are essentially > invisible to the normal modeset operation. You insert something into a fully ordered queue. That does break the entire concept and needs a pile of locks and stuff to make it work.
Exactly one lock. Well two if you could the spinlock to protect the committed_state pointer update from parallel updates touching the same kms object. That latter one could be removed if atomic wouldn't allow parallel commits to touch the same object.
Yes it's doable, but it's a redesign with all the implications of subtle breakage all over.
What? It doesn't really even do anything unless you do the duplicate_committed state(). Everything else is just assigning pointers. So unless there's some really obvious bug somewhere it can't break anything outside the GPU reset path. And really the only way to break to GPU reset path is to have actual bugs in the normal display commit code.
It's the gpu reset I'm worried about. There's no point in fixing it if it immediately breaks again.
While we do have open bugs for the current design. Rewriting the world to fix a bug needs seriously better justification imo.
> The one alternative proposed idea of allowing gem and kms sides go > out of whack scares me a bit. I think that might land us in more > trouble when I finally get around to making the video overlay a > drm_plane. We've run perfectly fine with this idea for years.
Not perfectly. I've had to fix it several times. And I don't think I was the only one.
The problem is that no one tests against gen4, and everyone forgets that it exists. That's why I'd like something with the minimal amount of invasiveness, since that would at least be easier to patch up when we inevitably break it. Also, something entirely contained to i915 conceptually, without imposing more restrictions on shared code.
> And I think trying to keep the GPU reset paths as similar as possible > between all the platforms would be a nice thing. Just whacking > everything on the head with a hammer on one platform but not on > another one seems to me like extra variation in behaviour that we > don't necessarily want. > > But like I said, if someone can come up with a better solution I > probably wouldn't object too much. It's not going to be coming from me > though since I have plenty of other things to do and vacation time is > coming up very soon. So unless someone else comes up with something nice > soon I think we should just go with my solution because a) it's already > available, and b) works quite decently from what I can see. I guess I'll have to retype the old thing in the new world, but it really shouldn't be more than the quick draft I've laid down in the old thread. This here is imo no-go with all the core changes, and even just done within i915 I think it's highly dubious that it provides a real benefit, since defacto it means we'll have to abandon the atomic helpers entirely.
Now I think you're just being difficult for the sake of it. Have you looked at the code at all? It's fully done from the atomic helpers right now. And even moving the committed state tracking to i915 wouldn't require abandoning the helpers. We could just update the committed state pointers when we call hw_done(), and we'd have to update the state seqno/age timestamp when we call swap_state(). That's all there is to this.
I'm concerned with the maintainenace burden you impose on all future i915 atomic work, that's all. Yes it looks simple to you and right now, but it's another little thing to keep working, and we're really good at breaking stuff all the time.
But if you strongly think this is the best possible approach overall, taking into account long-term impact, then go ahead with implementing this in i915. Adding it the concept of a committed state and being able to duplicate that and squeeze another commit in to the shared atomic helpers doesn't make sense imo. -Daniel
I think the problem is about struct_mutex usage by atomic commit during reset. GPU reset has to wait for all previous atomic updates to complete, but cleanup_planes and prepare_plane_fb both require struct_mutex, which can lead to a deadlock. #99093
The deadlocks I've seen recently didn't necessarily involve struct_mutex IIRC. Just the modeset locks.
The real fix is not taking struct_mutex during atomic commit, which will mean no deadlock can happen.
Is this the bug being fixed here or am I missing something?
This would avoid both struct_mutex and modeset locks in the display reset path, so I guess it should help with struct_mutex issues as well.
I think fixing i915 to not require struct_mutex for vma pinning/unpinning will be a better use of our time, and it should also fix all deadlocks. :)
It won't help with the modeset locks.
And it's far better than duplicating drm_atomic_commit functionality in our reset handlers.
Well I'm not actually duplicating anything. Just reusing what's already there. We just skip all the useless stuff and that allows us to skip the locking which is where all the problems have been up to now.
And it means we won't allow gem and kms to get totally out of sync, which I think will be a good thing for stuff like the video overlay which straddles both worlds.
On Mon, Jul 10, 2017 at 3:26 PM, Maarten Lankhorst maarten.lankhorst@linux.intel.com wrote:
The real fix is not taking struct_mutex during atomic commit, which will mean no deadlock can happen.
Is this the bug being fixed here or am I missing something?
This would avoid both struct_mutex and modeset locks in the display reset path, so I guess it should help with struct_mutex issues as well.
I think fixing i915 to not require struct_mutex for vma pinning/unpinning will be a better use of our time, and it should also fix all deadlocks. :)
And it's far better than duplicating drm_atomic_commit functionality in our reset handlers.
Part of the reasons I've asked is because I thought originally this regression was introduced in
4680816be336 ("drm/i915: Wait first for submission, before waiting for request completion") 221fe7994554 ("drm/i915: Perform a direct reset of the GPU from the waiter")
futuremore complicated by all the TDR work to no longer force-completing requests, but instead resubmitting them. The deadlock is a lot more than struct_mutex, since we can wait for requests without holding that one (through the recent-ish conversion to i915_sw_fence of the atomic commit path).
I'm still asking why we can't fix this regression again on the GEM side where it seems to have been introduced. We might or might still want to rewrite atomic to make it work better, and there's additional races with the nonblocking atomic commits (an oversight on my part, I also flat-out forget about gen4 gpu reset), but I still think the usual way should be 1. minimal regression fix 2. more extensive rework (if needed) of the lessons learned
So am I wrong with blaming this on GEM, or why can't the GEM folks fix this? I think removing the "this is a regression and blocking adding more machines to CI" pressure would make the discussion between Ville and me a lot more constructive too.
Thanks, Daniel
From: Ville Syrjälä ville.syrjala@linux.intel.com
Introduce an rw_semaphore to protect the display commits. All normal commits use down_read() and hence can proceed in parallel, but GPU reset will use down_write() making sure no other commits are in progress when we have to pull the plug on the display engine on pre-g4x platforms. There are no modeset/gem locks taken inside __intel_atomic_commit_tail() itself, and we wait for all dependencies before the down_read(), and thus there is no chance of deadlocks with this scheme.
During reset we will recommit the state that was commited last. Hence we require tracking which state that was, and we need a way to duplicate that state. That is now handled by the atomic core and helpers. We also have to be sure that none of the commit codepaths look up plane->state, crtc->state, etc. as that would lead us to pontetially commit some future state prematurely. crtc->config is actually fine since that gets update during the commit as well (although eventually we do want to rid ourselves of crtc->config).
I left out the state readout from the post-reset display reinitialization as that still likes to clobber crtc->state etc. If we make it use a free standing atomic state and mke sure it doesn't need any locks we could reintroduce it. For now I just mark the post-reset display state as dirty as possible to make sure we reinitialize everything.
One potential issue remains in the form of display detection. Either we need to protect that with the same rw_semaphore as well, or perhaps it would be enough to force gmbus into bitbanging mode while the reset is happening and we don't have interrupts, and just across the actual hardware GPU reset we could hold the gmbus mutex.
v2: Keep intel_prepare/finish_reset() outside struct_mutex (Chris) v3: Drop all the committed_state refactoring to make this less obnoxious to backport (Daniel) v4: Preserve the wedge timeout mechanism (Chris) v5: Go back to the full committed state tracking since it actually is needed
Signed-off-by: Ville Syrjälä ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/i915_drv.h | 2 + drivers/gpu/drm/i915/intel_display.c | 220 ++++++++++++++++++++++++----------- drivers/gpu/drm/i915/intel_sprite.c | 1 + 3 files changed, 157 insertions(+), 66 deletions(-)
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index baec61b078f5..432b356017ba 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2247,6 +2247,8 @@ struct drm_i915_private { struct drm_atomic_state *modeset_restore_state; struct drm_modeset_acquire_ctx reset_ctx;
+ struct rw_semaphore commit_sem; + struct list_head vm_list; /* Global list of all address spaces */ struct i915_ggtt ggtt; /* VM representing the global address space */
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index e9c85d7cbb3e..e8ff5095ede3 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -123,6 +123,7 @@ static void ironlake_pfit_enable(struct intel_crtc *crtc); static void intel_modeset_setup_hw_state(struct drm_device *dev, struct drm_modeset_acquire_ctx *ctx); static void intel_pre_disable_primary_noatomic(struct drm_crtc *crtc); +static void __intel_atomic_commit_tail(struct drm_atomic_state *state, bool is_reset);
struct intel_limit { struct { @@ -3432,15 +3433,15 @@ static void intel_update_primary_planes(struct drm_device *dev)
for_each_crtc(dev, crtc) { struct intel_plane *plane = to_intel_plane(crtc->primary); - struct intel_plane_state *plane_state = - to_intel_plane_state(plane->base.state); + const struct intel_plane_state *plane_state = + to_intel_plane_state(plane->base.committed_state);
if (plane_state->base.visible) { trace_intel_update_plane(&plane->base, to_intel_crtc(crtc));
plane->update_plane(plane, - to_intel_crtc_state(crtc->state), + to_intel_crtc_state(crtc->committed_state), plane_state); } } @@ -3491,27 +3492,97 @@ static bool gpu_reset_clobbers_display(struct drm_i915_private *dev_priv) INTEL_GEN(dev_priv) < 5 && !IS_G4X(dev_priv); }
-void intel_prepare_reset(struct drm_i915_private *dev_priv) +static void init_intel_state(struct intel_atomic_state *state) +{ + struct drm_crtc *crtc; + struct drm_crtc_state *old_crtc_state, *new_crtc_state; + int i; + + state->modeset = true; + + for_each_oldnew_crtc_in_state(&state->base, crtc, old_crtc_state, new_crtc_state, i) { + if (new_crtc_state->active) + state->active_crtcs |= 1 << i; + else + state->active_crtcs &= ~(1 << i); + + if (old_crtc_state->active != new_crtc_state->active) + state->active_pipe_changes |= drm_crtc_mask(crtc); + } +} + +static struct drm_atomic_state * +intel_duplicate_committed_state(struct drm_i915_private *dev_priv) { - struct drm_device *dev = &dev_priv->drm; - struct drm_modeset_acquire_ctx *ctx = &dev_priv->reset_ctx; struct drm_atomic_state *state; - int ret; + struct drm_crtc *crtc; + struct drm_crtc_state *crtc_state; + int i;
- /* - * Need mode_config.mutex so that we don't - * trample ongoing ->detect() and whatnot. - */ - mutex_lock(&dev->mode_config.mutex); - drm_modeset_acquire_init(ctx, 0); - while (1) { - ret = drm_modeset_lock_all_ctx(dev, ctx); - if (ret != -EDEADLK) - break; + state = drm_atomic_helper_duplicate_committed_state(&dev_priv->drm); + if (IS_ERR(state)) { + DRM_ERROR("Duplicating state failed with %ld\n", + PTR_ERR(state)); + return NULL; + } + + /* handle private obj states */ + /* FIXME could have the core track private objs too */ + for (i = 0; i < I915_MAX_PORTS; i++) { + struct intel_digital_port *intel_dig_port = + dev_priv->hotplug.irq_port[i]; + + if (!intel_dig_port || !intel_dig_port->dp.can_mst) + continue; + + drm_atomic_helper_duplicate_private_obj_committed_state(state, + &intel_dig_port->dp.mst_mgr.base); + } + + to_intel_atomic_state(state)->active_crtcs = 0; + to_intel_atomic_state(state)->cdclk.logical = dev_priv->cdclk.hw; + to_intel_atomic_state(state)->cdclk.actual = dev_priv->cdclk.hw; + + init_intel_state(to_intel_atomic_state(state)); + + /* force a full update */ + for_each_new_crtc_in_state(state, crtc, crtc_state, i) { + struct intel_crtc_state *intel_crtc_state = + to_intel_crtc_state(crtc_state); + + if (!crtc_state->active) + continue; + + crtc_state->mode_changed = true; + crtc_state->active_changed = true; + crtc_state->planes_changed = true; + crtc_state->connectors_changed = true; + crtc_state->color_mgmt_changed = true; + crtc_state->zpos_changed = true;
- drm_modeset_backoff(ctx); + intel_crtc_state->update_pipe = true; + intel_crtc_state->disable_lp_wm = true; + intel_crtc_state->disable_cxsr = true; + intel_crtc_state->update_wm_post = true; + intel_crtc_state->fb_changed = true; + intel_crtc_state->fifo_changed = true; + intel_crtc_state->wm.need_postvbl_update = true; }
+ return state; +} + +void intel_prepare_reset(struct drm_i915_private *dev_priv) +{ + struct drm_atomic_state *disable_state, *restore_state = NULL; + struct drm_crtc *crtc; + struct drm_crtc_state *crtc_state; + struct drm_plane *plane; + struct drm_plane_state *plane_state; + int i; + + down_write(&dev_priv->commit_sem); + /* reset doesn't touch the display, but flips might get nuked anyway, */ if (!i915.force_reset_modeset_test && !gpu_reset_clobbers_display(dev_priv)) @@ -3521,30 +3592,40 @@ void intel_prepare_reset(struct drm_i915_private *dev_priv) * Disabling the crtcs gracefully seems nicer. Also the * g33 docs say we should at least disable all the planes. */ - state = drm_atomic_helper_duplicate_state(dev, ctx); - if (IS_ERR(state)) { - ret = PTR_ERR(state); - DRM_ERROR("Duplicating state failed with %i\n", ret); - return; - } + disable_state = intel_duplicate_committed_state(dev_priv); + if (IS_ERR(disable_state)) + goto out;
- ret = drm_atomic_helper_disable_all(dev, ctx); - if (ret) { - DRM_ERROR("Suspending crtc's failed with %i\n", ret); - drm_atomic_state_put(state); - return; - } + to_intel_atomic_state(disable_state)->active_crtcs = 0;
- dev_priv->modeset_restore_state = state; - state->acquire_ctx = ctx; + for_each_new_crtc_in_state(disable_state, crtc, crtc_state, i) + crtc_state->active = false; + for_each_new_plane_in_state(disable_state, plane, plane_state, i) + plane_state->visible = false; + + __intel_atomic_commit_tail(disable_state, true); + + drm_atomic_helper_clean_committed_state(disable_state); + drm_atomic_state_put(disable_state); + + restore_state = intel_duplicate_committed_state(dev_priv); + if (IS_ERR(restore_state)) + restore_state = NULL; + + for_each_old_crtc_in_state(restore_state, crtc, crtc_state, i) + crtc_state->active = false; + for_each_old_plane_in_state(restore_state, plane, plane_state, i) + plane_state->visible = false; + +out: + dev_priv->modeset_restore_state = restore_state; }
void intel_finish_reset(struct drm_i915_private *dev_priv) { struct drm_device *dev = &dev_priv->drm; - struct drm_modeset_acquire_ctx *ctx = &dev_priv->reset_ctx; - struct drm_atomic_state *state = dev_priv->modeset_restore_state; - int ret; + struct drm_atomic_state *restore_state = + dev_priv->modeset_restore_state;
/* * Flips in the rings will be nuked by the reset, @@ -3557,7 +3638,7 @@ void intel_finish_reset(struct drm_i915_private *dev_priv)
/* reset doesn't touch the display */ if (!gpu_reset_clobbers_display(dev_priv)) { - if (!state) { + if (!restore_state) { /* * Flips in the rings have been nuked by the reset, * so update the base address of all primary @@ -3569,11 +3650,11 @@ void intel_finish_reset(struct drm_i915_private *dev_priv) */ intel_update_primary_planes(dev); } else { - ret = __intel_display_resume(dev, state, ctx); - if (ret) - DRM_ERROR("Restoring old state failed with %i\n", ret); + __intel_atomic_commit_tail(restore_state, true); } } else { + i915_redisable_vga(dev_priv); + /* * The display has been reset as well, * so need a full re-initialization. @@ -3589,18 +3670,17 @@ void intel_finish_reset(struct drm_i915_private *dev_priv) dev_priv->display.hpd_irq_setup(dev_priv); spin_unlock_irq(&dev_priv->irq_lock);
- ret = __intel_display_resume(dev, state, ctx); - if (ret) - DRM_ERROR("Restoring old state failed with %i\n", ret); + __intel_atomic_commit_tail(restore_state, true);
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); + if (restore_state) { + drm_atomic_helper_clean_committed_state(restore_state); + drm_atomic_state_put(restore_state); + } + + up_write(&dev_priv->commit_sem); }
static bool abort_flip_on_reset(struct intel_crtc *crtc) @@ -12609,29 +12689,18 @@ static int intel_modeset_checks(struct drm_atomic_state *state) { struct intel_atomic_state *intel_state = to_intel_atomic_state(state); struct drm_i915_private *dev_priv = to_i915(state->dev); - struct drm_crtc *crtc; - struct drm_crtc_state *old_crtc_state, *new_crtc_state; - int ret = 0, i; + int ret = 0;
if (!check_digital_port_conflicts(state)) { DRM_DEBUG_KMS("rejecting conflicting digital port configuration\n"); return -EINVAL; }
- intel_state->modeset = true; intel_state->active_crtcs = dev_priv->active_crtcs; intel_state->cdclk.logical = dev_priv->cdclk.logical; intel_state->cdclk.actual = dev_priv->cdclk.actual;
- for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { - if (new_crtc_state->active) - intel_state->active_crtcs |= 1 << i; - else - intel_state->active_crtcs &= ~(1 << i); - - if (old_crtc_state->active != new_crtc_state->active) - intel_state->active_pipe_changes |= drm_crtc_mask(crtc); - } + init_intel_state(intel_state);
/* * See if the config requires any additional preparation, e.g. @@ -13021,7 +13090,7 @@ static void intel_atomic_helper_free_state_worker(struct work_struct *work) intel_atomic_helper_free_state(dev_priv); }
-static void __intel_atomic_commit_tail(struct drm_atomic_state *state) +static void __intel_atomic_commit_tail(struct drm_atomic_state *state, bool is_reset) { struct drm_device *dev = state->dev; struct intel_atomic_state *intel_state = to_intel_atomic_state(state); @@ -13085,10 +13154,18 @@ static void __intel_atomic_commit_tail(struct drm_atomic_state *state)
/* Only after disabling all output pipelines that will be changed can we * update the the output configuration. */ - intel_modeset_update_crtc_state(state); + if (!is_reset) + intel_modeset_update_crtc_state(state);
if (intel_state->modeset) { - drm_atomic_helper_update_legacy_modeset_state(state->dev, state); + if (!is_reset) { + drm_atomic_helper_update_legacy_modeset_state(state->dev, state); + } else { + for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) { + if (new_crtc_state->enable) + drm_calc_timestamping_constants(crtc, &new_crtc_state->adjusted_mode); + } + }
intel_set_cdclk(dev_priv, &dev_priv->cdclk.actual);
@@ -13099,7 +13176,8 @@ static void __intel_atomic_commit_tail(struct drm_atomic_state *state) if (!intel_can_enable_sagv(state)) intel_disable_sagv(dev_priv);
- intel_modeset_verify_disabled(dev, state); + if (!is_reset) + intel_modeset_verify_disabled(dev, state); }
/* Complete the events for pipes that have now been disabled */ @@ -13152,7 +13230,8 @@ static void __intel_atomic_commit_tail(struct drm_atomic_state *state) if (put_domains[i]) modeset_put_power_domains(dev_priv, put_domains[i]);
- intel_modeset_verify_crtc(crtc, state, old_crtc_state, new_crtc_state); + if (!is_reset) + intel_modeset_verify_crtc(crtc, state, old_crtc_state, new_crtc_state); }
if (intel_state->modeset && intel_can_enable_sagv(state)) @@ -13177,10 +13256,14 @@ static void intel_atomic_commit_tail(struct drm_atomic_state *state)
drm_atomic_helper_wait_for_dependencies(state);
- __intel_atomic_commit_tail(state); + down_read(&dev_priv->commit_sem); + + __intel_atomic_commit_tail(state, false);
drm_atomic_helper_commit_hw_done(state);
+ up_read(&dev_priv->commit_sem); + mutex_lock(&dev->struct_mutex); drm_atomic_helper_cleanup_planes(dev, state); mutex_unlock(&dev->struct_mutex); @@ -13779,6 +13862,7 @@ intel_primary_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe) }
primary->base.state = &state->base; + primary->base.committed_state = &state->base;
primary->can_scale = false; primary->max_downscale = 1; @@ -13892,6 +13976,7 @@ intel_cursor_plane_create(struct drm_i915_private *dev_priv, }
cursor->base.state = &state->base; + cursor->base.committed_state = &state->base;
cursor->can_scale = false; cursor->max_downscale = 1; @@ -13986,6 +14071,7 @@ static int intel_crtc_init(struct drm_i915_private *dev_priv, enum pipe pipe) } intel_crtc->config = crtc_state; intel_crtc->base.state = &crtc_state->base; + intel_crtc->base.committed_state = &crtc_state->base; crtc_state->base.crtc = &intel_crtc->base;
primary = intel_primary_plane_create(dev_priv, pipe); @@ -15059,6 +15145,8 @@ int intel_modeset_init(struct drm_device *dev) INIT_WORK(&dev_priv->atomic_helper.free_work, intel_atomic_helper_free_state_worker);
+ init_rwsem(&dev_priv->commit_sem); + intel_init_quirks(dev);
intel_init_pm(dev_priv); diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index aed4fa833b48..9d68db31a0f1 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -1097,6 +1097,7 @@ intel_sprite_plane_create(struct drm_i915_private *dev_priv, goto fail; } intel_plane->base.state = &state->base; + intel_plane->base.committed_state = &state->base;
if (INTEL_GEN(dev_priv) >= 9) { intel_plane->can_scale = true;
On Thu, Jul 06, 2017 at 11:24:42PM +0300, ville.syrjala@linux.intel.com wrote:
From: Ville Syrjälä ville.syrjala@linux.intel.com
Introduce an rw_semaphore to protect the display commits. All normal commits use down_read() and hence can proceed in parallel, but GPU reset will use down_write() making sure no other commits are in progress when we have to pull the plug on the display engine on pre-g4x platforms. There are no modeset/gem locks taken inside __intel_atomic_commit_tail() itself, and we wait for all dependencies before the down_read(), and thus there is no chance of deadlocks with this scheme.
After all these discussions I get the feeling the deadlocks is a lot more involved than what I thought it is. But your patch doesn't really describe it. Can you pls fix that?
During reset we will recommit the state that was commited last. Hence we require tracking which state that was, and we need a way to duplicate that state. That is now handled by the atomic core and helpers. We also have to be sure that none of the commit codepaths look up plane->state, crtc->state, etc. as that would lead us to pontetially commit some future state prematurely. crtc->config is actually fine since that gets update during the commit as well (although eventually we do want to rid ourselves of crtc->config).
I left out the state readout from the post-reset display reinitialization as that still likes to clobber crtc->state etc. If we make it use a free standing atomic state and mke sure it doesn't need any locks we could reintroduce it. For now I just mark the post-reset display state as dirty as possible to make sure we reinitialize everything.
One potential issue remains in the form of display detection. Either we need to protect that with the same rw_semaphore as well, or perhaps it would be enough to force gmbus into bitbanging mode while the reset is happening and we don't have interrupts, and just across the actual hardware GPU reset we could hold the gmbus mutex.
Can you pls also elaborate on what's the problem here?
The other problem we've never fixed is that by shutting down the pipe we also kill vblank interrupts, and userspace can notice that, just as an aside.
Cheers, Daniel
v2: Keep intel_prepare/finish_reset() outside struct_mutex (Chris) v3: Drop all the committed_state refactoring to make this less obnoxious to backport (Daniel) v4: Preserve the wedge timeout mechanism (Chris) v5: Go back to the full committed state tracking since it actually is needed
Signed-off-by: Ville Syrjälä ville.syrjala@linux.intel.com
drivers/gpu/drm/i915/i915_drv.h | 2 + drivers/gpu/drm/i915/intel_display.c | 220 ++++++++++++++++++++++++----------- drivers/gpu/drm/i915/intel_sprite.c | 1 + 3 files changed, 157 insertions(+), 66 deletions(-)
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index baec61b078f5..432b356017ba 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2247,6 +2247,8 @@ struct drm_i915_private { struct drm_atomic_state *modeset_restore_state; struct drm_modeset_acquire_ctx reset_ctx;
- struct rw_semaphore commit_sem;
- struct list_head vm_list; /* Global list of all address spaces */ struct i915_ggtt ggtt; /* VM representing the global address space */
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index e9c85d7cbb3e..e8ff5095ede3 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -123,6 +123,7 @@ static void ironlake_pfit_enable(struct intel_crtc *crtc); static void intel_modeset_setup_hw_state(struct drm_device *dev, struct drm_modeset_acquire_ctx *ctx); static void intel_pre_disable_primary_noatomic(struct drm_crtc *crtc); +static void __intel_atomic_commit_tail(struct drm_atomic_state *state, bool is_reset);
struct intel_limit { struct { @@ -3432,15 +3433,15 @@ static void intel_update_primary_planes(struct drm_device *dev)
for_each_crtc(dev, crtc) { struct intel_plane *plane = to_intel_plane(crtc->primary);
struct intel_plane_state *plane_state =
to_intel_plane_state(plane->base.state);
const struct intel_plane_state *plane_state =
to_intel_plane_state(plane->base.committed_state);
if (plane_state->base.visible) { trace_intel_update_plane(&plane->base, to_intel_crtc(crtc));
plane->update_plane(plane,
to_intel_crtc_state(crtc->state),
} }to_intel_crtc_state(crtc->committed_state), plane_state);
@@ -3491,27 +3492,97 @@ static bool gpu_reset_clobbers_display(struct drm_i915_private *dev_priv) INTEL_GEN(dev_priv) < 5 && !IS_G4X(dev_priv); }
-void intel_prepare_reset(struct drm_i915_private *dev_priv) +static void init_intel_state(struct intel_atomic_state *state) +{
- struct drm_crtc *crtc;
- struct drm_crtc_state *old_crtc_state, *new_crtc_state;
- int i;
- state->modeset = true;
- for_each_oldnew_crtc_in_state(&state->base, crtc, old_crtc_state, new_crtc_state, i) {
if (new_crtc_state->active)
state->active_crtcs |= 1 << i;
else
state->active_crtcs &= ~(1 << i);
if (old_crtc_state->active != new_crtc_state->active)
state->active_pipe_changes |= drm_crtc_mask(crtc);
- }
+}
+static struct drm_atomic_state * +intel_duplicate_committed_state(struct drm_i915_private *dev_priv) {
- struct drm_device *dev = &dev_priv->drm;
- struct drm_modeset_acquire_ctx *ctx = &dev_priv->reset_ctx; struct drm_atomic_state *state;
- int ret;
- struct drm_crtc *crtc;
- struct drm_crtc_state *crtc_state;
- int i;
- /*
* Need mode_config.mutex so that we don't
* trample ongoing ->detect() and whatnot.
*/
- mutex_lock(&dev->mode_config.mutex);
- drm_modeset_acquire_init(ctx, 0);
- while (1) {
ret = drm_modeset_lock_all_ctx(dev, ctx);
if (ret != -EDEADLK)
break;
- state = drm_atomic_helper_duplicate_committed_state(&dev_priv->drm);
- if (IS_ERR(state)) {
DRM_ERROR("Duplicating state failed with %ld\n",
PTR_ERR(state));
return NULL;
- }
- /* handle private obj states */
- /* FIXME could have the core track private objs too */
- for (i = 0; i < I915_MAX_PORTS; i++) {
struct intel_digital_port *intel_dig_port =
dev_priv->hotplug.irq_port[i];
if (!intel_dig_port || !intel_dig_port->dp.can_mst)
continue;
drm_atomic_helper_duplicate_private_obj_committed_state(state,
&intel_dig_port->dp.mst_mgr.base);
- }
- to_intel_atomic_state(state)->active_crtcs = 0;
- to_intel_atomic_state(state)->cdclk.logical = dev_priv->cdclk.hw;
- to_intel_atomic_state(state)->cdclk.actual = dev_priv->cdclk.hw;
- init_intel_state(to_intel_atomic_state(state));
- /* force a full update */
- for_each_new_crtc_in_state(state, crtc, crtc_state, i) {
struct intel_crtc_state *intel_crtc_state =
to_intel_crtc_state(crtc_state);
if (!crtc_state->active)
continue;
crtc_state->mode_changed = true;
crtc_state->active_changed = true;
crtc_state->planes_changed = true;
crtc_state->connectors_changed = true;
crtc_state->color_mgmt_changed = true;
crtc_state->zpos_changed = true;
drm_modeset_backoff(ctx);
intel_crtc_state->update_pipe = true;
intel_crtc_state->disable_lp_wm = true;
intel_crtc_state->disable_cxsr = true;
intel_crtc_state->update_wm_post = true;
intel_crtc_state->fb_changed = true;
intel_crtc_state->fifo_changed = true;
intel_crtc_state->wm.need_postvbl_update = true;
}
return state;
+}
+void intel_prepare_reset(struct drm_i915_private *dev_priv) +{
- struct drm_atomic_state *disable_state, *restore_state = NULL;
- struct drm_crtc *crtc;
- struct drm_crtc_state *crtc_state;
- struct drm_plane *plane;
- struct drm_plane_state *plane_state;
- int i;
- down_write(&dev_priv->commit_sem);
- /* reset doesn't touch the display, but flips might get nuked anyway, */ if (!i915.force_reset_modeset_test && !gpu_reset_clobbers_display(dev_priv))
@@ -3521,30 +3592,40 @@ void intel_prepare_reset(struct drm_i915_private *dev_priv) * Disabling the crtcs gracefully seems nicer. Also the * g33 docs say we should at least disable all the planes. */
- state = drm_atomic_helper_duplicate_state(dev, ctx);
- if (IS_ERR(state)) {
ret = PTR_ERR(state);
DRM_ERROR("Duplicating state failed with %i\n", ret);
return;
- }
- disable_state = intel_duplicate_committed_state(dev_priv);
- if (IS_ERR(disable_state))
goto out;
- ret = drm_atomic_helper_disable_all(dev, ctx);
- if (ret) {
DRM_ERROR("Suspending crtc's failed with %i\n", ret);
drm_atomic_state_put(state);
return;
- }
- to_intel_atomic_state(disable_state)->active_crtcs = 0;
- dev_priv->modeset_restore_state = state;
- state->acquire_ctx = ctx;
- for_each_new_crtc_in_state(disable_state, crtc, crtc_state, i)
crtc_state->active = false;
- for_each_new_plane_in_state(disable_state, plane, plane_state, i)
plane_state->visible = false;
- __intel_atomic_commit_tail(disable_state, true);
- drm_atomic_helper_clean_committed_state(disable_state);
- drm_atomic_state_put(disable_state);
- restore_state = intel_duplicate_committed_state(dev_priv);
- if (IS_ERR(restore_state))
restore_state = NULL;
- for_each_old_crtc_in_state(restore_state, crtc, crtc_state, i)
crtc_state->active = false;
- for_each_old_plane_in_state(restore_state, plane, plane_state, i)
plane_state->visible = false;
+out:
- dev_priv->modeset_restore_state = restore_state;
}
void intel_finish_reset(struct drm_i915_private *dev_priv) { struct drm_device *dev = &dev_priv->drm;
- struct drm_modeset_acquire_ctx *ctx = &dev_priv->reset_ctx;
- struct drm_atomic_state *state = dev_priv->modeset_restore_state;
- int ret;
struct drm_atomic_state *restore_state =
dev_priv->modeset_restore_state;
/*
- Flips in the rings will be nuked by the reset,
@@ -3557,7 +3638,7 @@ void intel_finish_reset(struct drm_i915_private *dev_priv)
/* reset doesn't touch the display */ if (!gpu_reset_clobbers_display(dev_priv)) {
if (!state) {
if (!restore_state) { /* * Flips in the rings have been nuked by the reset, * so update the base address of all primary
@@ -3569,11 +3650,11 @@ void intel_finish_reset(struct drm_i915_private *dev_priv) */ intel_update_primary_planes(dev); } else {
ret = __intel_display_resume(dev, state, ctx);
if (ret)
DRM_ERROR("Restoring old state failed with %i\n", ret);
} } else {__intel_atomic_commit_tail(restore_state, true);
i915_redisable_vga(dev_priv);
- /*
- The display has been reset as well,
- so need a full re-initialization.
@@ -3589,18 +3670,17 @@ void intel_finish_reset(struct drm_i915_private *dev_priv) dev_priv->display.hpd_irq_setup(dev_priv); spin_unlock_irq(&dev_priv->irq_lock);
ret = __intel_display_resume(dev, state, ctx);
if (ret)
DRM_ERROR("Restoring old state failed with %i\n", ret);
__intel_atomic_commit_tail(restore_state, true);
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);
- if (restore_state) {
drm_atomic_helper_clean_committed_state(restore_state);
drm_atomic_state_put(restore_state);
- }
- up_write(&dev_priv->commit_sem);
}
static bool abort_flip_on_reset(struct intel_crtc *crtc) @@ -12609,29 +12689,18 @@ static int intel_modeset_checks(struct drm_atomic_state *state) { struct intel_atomic_state *intel_state = to_intel_atomic_state(state); struct drm_i915_private *dev_priv = to_i915(state->dev);
- struct drm_crtc *crtc;
- struct drm_crtc_state *old_crtc_state, *new_crtc_state;
- int ret = 0, i;
int ret = 0;
if (!check_digital_port_conflicts(state)) { DRM_DEBUG_KMS("rejecting conflicting digital port configuration\n"); return -EINVAL; }
intel_state->modeset = true; intel_state->active_crtcs = dev_priv->active_crtcs; intel_state->cdclk.logical = dev_priv->cdclk.logical; intel_state->cdclk.actual = dev_priv->cdclk.actual;
for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
if (new_crtc_state->active)
intel_state->active_crtcs |= 1 << i;
else
intel_state->active_crtcs &= ~(1 << i);
if (old_crtc_state->active != new_crtc_state->active)
intel_state->active_pipe_changes |= drm_crtc_mask(crtc);
}
init_intel_state(intel_state);
/*
- See if the config requires any additional preparation, e.g.
@@ -13021,7 +13090,7 @@ static void intel_atomic_helper_free_state_worker(struct work_struct *work) intel_atomic_helper_free_state(dev_priv); }
-static void __intel_atomic_commit_tail(struct drm_atomic_state *state) +static void __intel_atomic_commit_tail(struct drm_atomic_state *state, bool is_reset) { struct drm_device *dev = state->dev; struct intel_atomic_state *intel_state = to_intel_atomic_state(state); @@ -13085,10 +13154,18 @@ static void __intel_atomic_commit_tail(struct drm_atomic_state *state)
/* Only after disabling all output pipelines that will be changed can we * update the the output configuration. */
- intel_modeset_update_crtc_state(state);
if (!is_reset)
intel_modeset_update_crtc_state(state);
if (intel_state->modeset) {
drm_atomic_helper_update_legacy_modeset_state(state->dev, state);
if (!is_reset) {
drm_atomic_helper_update_legacy_modeset_state(state->dev, state);
} else {
for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) {
if (new_crtc_state->enable)
drm_calc_timestamping_constants(crtc, &new_crtc_state->adjusted_mode);
}
}
intel_set_cdclk(dev_priv, &dev_priv->cdclk.actual);
@@ -13099,7 +13176,8 @@ static void __intel_atomic_commit_tail(struct drm_atomic_state *state) if (!intel_can_enable_sagv(state)) intel_disable_sagv(dev_priv);
intel_modeset_verify_disabled(dev, state);
if (!is_reset)
intel_modeset_verify_disabled(dev, state);
}
/* Complete the events for pipes that have now been disabled */
@@ -13152,7 +13230,8 @@ static void __intel_atomic_commit_tail(struct drm_atomic_state *state) if (put_domains[i]) modeset_put_power_domains(dev_priv, put_domains[i]);
intel_modeset_verify_crtc(crtc, state, old_crtc_state, new_crtc_state);
if (!is_reset)
intel_modeset_verify_crtc(crtc, state, old_crtc_state, new_crtc_state);
}
if (intel_state->modeset && intel_can_enable_sagv(state))
@@ -13177,10 +13256,14 @@ static void intel_atomic_commit_tail(struct drm_atomic_state *state)
drm_atomic_helper_wait_for_dependencies(state);
- __intel_atomic_commit_tail(state);
down_read(&dev_priv->commit_sem);
__intel_atomic_commit_tail(state, false);
drm_atomic_helper_commit_hw_done(state);
up_read(&dev_priv->commit_sem);
mutex_lock(&dev->struct_mutex); drm_atomic_helper_cleanup_planes(dev, state); mutex_unlock(&dev->struct_mutex);
@@ -13779,6 +13862,7 @@ intel_primary_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe) }
primary->base.state = &state->base;
primary->base.committed_state = &state->base;
primary->can_scale = false; primary->max_downscale = 1;
@@ -13892,6 +13976,7 @@ intel_cursor_plane_create(struct drm_i915_private *dev_priv, }
cursor->base.state = &state->base;
cursor->base.committed_state = &state->base;
cursor->can_scale = false; cursor->max_downscale = 1;
@@ -13986,6 +14071,7 @@ static int intel_crtc_init(struct drm_i915_private *dev_priv, enum pipe pipe) } intel_crtc->config = crtc_state; intel_crtc->base.state = &crtc_state->base;
intel_crtc->base.committed_state = &crtc_state->base; crtc_state->base.crtc = &intel_crtc->base;
primary = intel_primary_plane_create(dev_priv, pipe);
@@ -15059,6 +15145,8 @@ int intel_modeset_init(struct drm_device *dev) INIT_WORK(&dev_priv->atomic_helper.free_work, intel_atomic_helper_free_state_worker);
init_rwsem(&dev_priv->commit_sem);
intel_init_quirks(dev);
intel_init_pm(dev_priv);
diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index aed4fa833b48..9d68db31a0f1 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -1097,6 +1097,7 @@ intel_sprite_plane_create(struct drm_i915_private *dev_priv, goto fail; } intel_plane->base.state = &state->base;
intel_plane->base.committed_state = &state->base;
if (INTEL_GEN(dev_priv) >= 9) { intel_plane->can_scale = true;
-- 2.13.0
dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
dri-devel@lists.freedesktop.org