Commit 94f05024 authored by Daniel Vetter's avatar Daniel Vetter

drm/i915: nonblocking commit

Simply split intel_atomic_commit in half and place the new
nonblocking commit helpers at the right spots.

NOTE: There's still trouble with obj->frontbuffer bits getting mangled
when pipelining atomic commits.

v2:
- Remove the check for nonblocking which returned -EINVAL.
- Do wait for requests in the worker thread before committing
  hw state.

v3: Move hw_done after the optimize_wm/post_plane_update step, plus
add FIXME comment how to fix that up again properly.

v4: Update FIXME for intel_atomic_commit - more stuff works now.

v5: Still reject nonblocking modeset commits (Maarten).

v6: Use intel_state->modeset (Maarten).

Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Reviewed-by: default avatarMaarten Lankhorst <maarten.lankhorst@linux.intel.com>
Signed-off-by: default avatarDaniel Vetter <daniel.vetter@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1465920060-6388-1-git-send-email-daniel.vetter@ffwll.ch
parent faf68d92
...@@ -13571,11 +13571,6 @@ static int intel_atomic_prepare_commit(struct drm_device *dev, ...@@ -13571,11 +13571,6 @@ static int intel_atomic_prepare_commit(struct drm_device *dev,
struct drm_crtc *crtc; struct drm_crtc *crtc;
int i, ret; int i, ret;
if (nonblock) {
DRM_DEBUG_KMS("i915 does not yet support nonblocking commit\n");
return -EINVAL;
}
for_each_crtc_in_state(state, crtc, crtc_state, i) { for_each_crtc_in_state(state, crtc, crtc_state, i) {
if (state->legacy_cursor_update) if (state->legacy_cursor_update)
continue; continue;
...@@ -13694,50 +13689,34 @@ static bool needs_vblank_wait(struct intel_crtc_state *crtc_state) ...@@ -13694,50 +13689,34 @@ static bool needs_vblank_wait(struct intel_crtc_state *crtc_state)
return false; return false;
} }
/** static void intel_atomic_commit_tail(struct drm_atomic_state *state)
* intel_atomic_commit - commit validated state object
* @dev: DRM device
* @state: the top-level driver state object
* @nonblock: nonblocking commit
*
* This function commits a top-level state object that has been validated
* with drm_atomic_helper_check().
*
* FIXME: Atomic modeset support for i915 is not yet complete. At the moment
* we can only handle plane-related operations and do not yet support
* nonblocking commit.
*
* RETURNS
* Zero for success or -errno.
*/
static int intel_atomic_commit(struct drm_device *dev,
struct drm_atomic_state *state,
bool nonblock)
{ {
struct drm_device *dev = state->dev;
struct intel_atomic_state *intel_state = to_intel_atomic_state(state); struct intel_atomic_state *intel_state = to_intel_atomic_state(state);
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_crtc_state *old_crtc_state; struct drm_crtc_state *old_crtc_state;
struct drm_crtc *crtc; struct drm_crtc *crtc;
struct intel_crtc_state *intel_cstate; struct intel_crtc_state *intel_cstate;
int ret = 0, i; struct drm_plane *plane;
struct drm_plane_state *plane_state;
bool hw_check = intel_state->modeset; bool hw_check = intel_state->modeset;
unsigned long put_domains[I915_MAX_PIPES] = {}; unsigned long put_domains[I915_MAX_PIPES] = {};
unsigned crtc_vblank_mask = 0; unsigned crtc_vblank_mask = 0;
int i, ret;
ret = drm_atomic_helper_setup_commit(state, nonblock); for_each_plane_in_state(state, plane, plane_state, i) {
if (ret) struct intel_plane_state *intel_plane_state =
return ret; to_intel_plane_state(plane_state);
ret = intel_atomic_prepare_commit(dev, state, nonblock); if (!intel_plane_state->wait_req)
if (ret) { continue;
DRM_DEBUG_ATOMIC("Preparing state failed with %i\n", ret);
return ret;
}
drm_atomic_helper_swap_state(state, true); ret = __i915_wait_request(intel_plane_state->wait_req,
dev_priv->wm.distrust_bios_wm = false; true, NULL, NULL);
dev_priv->wm.skl_results = intel_state->wm_results; /* EIO should be eaten, and we can't get interrupted in the
intel_shared_dpll_commit(state); * worker, and blocking commits have waited already. */
WARN_ON(ret);
}
drm_atomic_helper_wait_for_dependencies(state); drm_atomic_helper_wait_for_dependencies(state);
...@@ -13836,8 +13815,15 @@ static int intel_atomic_commit(struct drm_device *dev, ...@@ -13836,8 +13815,15 @@ static int intel_atomic_commit(struct drm_device *dev,
crtc_vblank_mask |= 1 << i; crtc_vblank_mask |= 1 << i;
} }
drm_atomic_helper_commit_hw_done(state); /* FIXME: We should call drm_atomic_helper_commit_hw_done() here
* already, but still need the state for the delayed optimization. To
* fix this:
* - wrap the optimization/post_plane_update stuff into a per-crtc work.
* - schedule that vblank worker _before_ calling hw_done
* - at the start of commit_tail, cancel it _synchrously
* - switch over to the vblank wait helper in the core after that since
* we don't need out special handling any more.
*/
if (!state->legacy_cursor_update) if (!state->legacy_cursor_update)
intel_atomic_wait_for_vblanks(dev, dev_priv, crtc_vblank_mask); intel_atomic_wait_for_vblanks(dev, dev_priv, crtc_vblank_mask);
...@@ -13864,6 +13850,8 @@ static int intel_atomic_commit(struct drm_device *dev, ...@@ -13864,6 +13850,8 @@ static int intel_atomic_commit(struct drm_device *dev,
intel_modeset_verify_crtc(crtc, old_crtc_state, crtc->state); intel_modeset_verify_crtc(crtc, old_crtc_state, crtc->state);
} }
drm_atomic_helper_commit_hw_done(state);
if (intel_state->modeset) if (intel_state->modeset)
intel_display_power_put(dev_priv, POWER_DOMAIN_MODESET); intel_display_power_put(dev_priv, POWER_DOMAIN_MODESET);
...@@ -13887,6 +13875,66 @@ static int intel_atomic_commit(struct drm_device *dev, ...@@ -13887,6 +13875,66 @@ static int intel_atomic_commit(struct drm_device *dev,
* can happen also when the device is completely off. * can happen also when the device is completely off.
*/ */
intel_uncore_arm_unclaimed_mmio_detection(dev_priv); intel_uncore_arm_unclaimed_mmio_detection(dev_priv);
}
static void intel_atomic_commit_work(struct work_struct *work)
{
struct drm_atomic_state *state = container_of(work,
struct drm_atomic_state,
commit_work);
intel_atomic_commit_tail(state);
}
/**
* intel_atomic_commit - commit validated state object
* @dev: DRM device
* @state: the top-level driver state object
* @nonblock: nonblocking commit
*
* This function commits a top-level state object that has been validated
* with drm_atomic_helper_check().
*
* FIXME: Atomic modeset support for i915 is not yet complete. At the moment
* nonblocking commits are only safe for pure plane updates. Everything else
* should work though.
*
* RETURNS
* Zero for success or -errno.
*/
static int intel_atomic_commit(struct drm_device *dev,
struct drm_atomic_state *state,
bool nonblock)
{
struct intel_atomic_state *intel_state = to_intel_atomic_state(state);
struct drm_i915_private *dev_priv = dev->dev_private;
int ret = 0;
if (intel_state->modeset && nonblock) {
DRM_DEBUG_KMS("nonblocking commit for modeset not yet implemented.\n");
return -EINVAL;
}
ret = drm_atomic_helper_setup_commit(state, nonblock);
if (ret)
return ret;
INIT_WORK(&state->commit_work, intel_atomic_commit_work);
ret = intel_atomic_prepare_commit(dev, state, nonblock);
if (ret) {
DRM_DEBUG_ATOMIC("Preparing state failed with %i\n", ret);
return ret;
}
drm_atomic_helper_swap_state(state, true);
dev_priv->wm.distrust_bios_wm = false;
dev_priv->wm.skl_results = intel_state->wm_results;
intel_shared_dpll_commit(state);
if (nonblock)
queue_work(system_unbound_wq, &state->commit_work);
else
intel_atomic_commit_tail(state);
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment