[PATCH 28/33] drm/i915: Plane granularity for atomic modesetting
Chris Wilson
chris at chris-wilson.co.uk
Fri Sep 16 13:47:40 UTC 2016
Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
---
drivers/gpu/drm/i915/i915_sw_fence.c | 8 +--
drivers/gpu/drm/i915/i915_sw_fence.h | 9 +++
drivers/gpu/drm/i915/intel_display.c | 135 +++++++++++++++++++++++++++--------
drivers/gpu/drm/i915/intel_drv.h | 2 +
drivers/gpu/drm/i915/intel_sprite.c | 1 +
5 files changed, 118 insertions(+), 37 deletions(-)
diff --git a/drivers/gpu/drm/i915/i915_sw_fence.c b/drivers/gpu/drm/i915/i915_sw_fence.c
index 1fd20b69feea..6a977fc87669 100644
--- a/drivers/gpu/drm/i915/i915_sw_fence.c
+++ b/drivers/gpu/drm/i915/i915_sw_fence.c
@@ -38,17 +38,11 @@ static void i915_sw_fence_free(struct kref *kref)
kfree(fence);
}
-static void i915_sw_fence_put(struct i915_sw_fence *fence)
+void i915_sw_fence_put(struct i915_sw_fence *fence)
{
kref_put(&fence->kref, i915_sw_fence_free);
}
-static struct i915_sw_fence *i915_sw_fence_get(struct i915_sw_fence *fence)
-{
- kref_get(&fence->kref);
- return fence;
-}
-
static void __i915_sw_fence_wake_up_all(struct i915_sw_fence *fence,
struct list_head *continuation)
{
diff --git a/drivers/gpu/drm/i915/i915_sw_fence.h b/drivers/gpu/drm/i915/i915_sw_fence.h
index d221df381ec2..c098164af126 100644
--- a/drivers/gpu/drm/i915/i915_sw_fence.h
+++ b/drivers/gpu/drm/i915/i915_sw_fence.h
@@ -43,6 +43,15 @@ typedef int (*i915_sw_fence_notify_t)(struct i915_sw_fence *,
void i915_sw_fence_init(struct i915_sw_fence *fence, i915_sw_fence_notify_t fn);
void i915_sw_fence_commit(struct i915_sw_fence *fence);
+static inline struct i915_sw_fence *
+i915_sw_fence_get(struct i915_sw_fence *fence)
+{
+ kref_get(&fence->kref);
+ return fence;
+}
+
+void i915_sw_fence_put(struct i915_sw_fence *fence);
+
int i915_sw_fence_await_sw_fence(struct i915_sw_fence *fence,
struct i915_sw_fence *after,
wait_queue_t *wq, gfp_t gfp);
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 26f4d1acd96e..ae2020c9dd44 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -14132,10 +14132,53 @@ intel_cleanup_plane_fb(struct drm_plane *plane,
intel_unpin_fb_vma(vma);
}
+static void track_last_commit(struct drm_plane *plane,
+ struct drm_atomic_state *state)
+{
+ struct intel_plane *intel_plane = to_intel_plane(plane);
+ struct intel_atomic_state *intel_state = to_intel_atomic_state(state);
+ struct i915_sw_fence *fence;
+
+ if (intel_plane->last_commit == &intel_state->commit_done)
+ return;
+
+ i915_sw_fence_get(&intel_state->commit_done);
+
+ spin_lock(&intel_plane->commit_lock);
+ fence = intel_plane->last_commit;
+ intel_plane->last_commit = &intel_state->commit_done;
+ spin_unlock(&intel_plane->commit_lock);
+
+ if (fence) {
+ i915_sw_fence_await_sw_fence(&intel_state->commit_ready, fence,
+ NULL, GFP_KERNEL);
+ i915_sw_fence_put(fence);
+ }
+}
+
+static void track_last_modeset(struct drm_atomic_state *state,
+ struct drm_crtc *crtc,
+ struct drm_crtc_state *crtc_state)
+{
+ struct drm_plane *plane;
+
+ if (!needs_modeset(crtc_state))
+ return;
+
+ drm_for_each_plane(plane, state->dev) {
+ if (to_intel_plane(plane)->pipe != drm_crtc_index(crtc))
+ continue;
+
+ track_last_commit(plane, state);
+ }
+}
+
static int intel_atomic_commit_prepare_planes(struct drm_atomic_state *state)
{
struct drm_plane *plane;
struct drm_plane_state *plane_state;
+ struct drm_crtc *crtc;
+ struct drm_crtc_state *crtc_state;
int i, j, ret;
ret = mutex_lock_interruptible(&state->dev->struct_mutex);
@@ -14145,16 +14188,23 @@ static int intel_atomic_commit_prepare_planes(struct drm_atomic_state *state)
for_each_plane_in_state(state, plane, plane_state, i) {
ret = intel_prepare_plane_fb(plane, plane_state);
if (ret)
- break;
+ goto err;
}
+ mutex_unlock(&state->dev->struct_mutex);
- if (ret) {
- for_each_plane_in_state(state, plane, plane_state, j) {
- if (j >= i)
- break;
+ for_each_crtc_in_state(state, crtc, crtc_state, i)
+ track_last_modeset(state, crtc, crtc_state);
+ for_each_plane_in_state(state, plane, plane_state, i)
+ track_last_commit(plane, state);
- intel_cleanup_plane_fb(plane, plane_state);
- }
+ return 0;
+
+err:
+ for_each_plane_in_state(state, plane, plane_state, j) {
+ if (j >= i)
+ break;
+
+ intel_cleanup_plane_fb(plane, plane_state);
}
mutex_unlock(&state->dev->struct_mutex);
@@ -14176,10 +14226,9 @@ static void intel_atomic_commit_cleanup_planes(struct drm_atomic_state *state)
mutex_unlock(&state->dev->struct_mutex);
}
-static int intel_atomic_prepare_commit(struct drm_device *dev,
- struct drm_atomic_state *state)
+static int intel_atomic_prepare_commit(struct drm_atomic_state *state)
{
- struct drm_i915_private *dev_priv = to_i915(dev);
+ struct drm_i915_private *dev_priv = to_i915(state->dev);
struct drm_crtc_state *crtc_state;
struct drm_crtc *crtc;
int i, ret;
@@ -14379,6 +14428,18 @@ static void skl_update_crtcs(struct drm_atomic_state *state,
} while (progress);
}
+static void intel_atomic_track_fbs(struct drm_atomic_state *state)
+{
+ struct drm_plane_state *old_plane_state;
+ struct drm_plane *plane;
+ int i;
+
+ for_each_plane_in_state(state, plane, old_plane_state, i)
+ i915_gem_track_fb(intel_fb_obj(old_plane_state->fb),
+ intel_fb_obj(plane->state->fb),
+ to_intel_plane(plane)->frontbuffer_bit);
+}
+
static void intel_atomic_commit_tail(struct drm_atomic_state *state)
{
struct drm_device *dev = state->dev;
@@ -14392,7 +14453,11 @@ 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);
+ drm_atomic_helper_swap_state(state, false);
+ dev_priv->wm.distrust_bios_wm = false;
+ dev_priv->wm.skl_results = intel_state->wm_results;
+ intel_shared_dpll_commit(state);
+ intel_atomic_track_fbs(state);
if (intel_state->modeset) {
memcpy(dev_priv->min_pixclk, intel_state->min_pixclk,
@@ -14517,6 +14582,7 @@ static void intel_atomic_commit_tail(struct drm_atomic_state *state)
skl_can_enable_sagv(state))
skl_enable_sagv(dev_priv);
+ i915_sw_fence_commit(&intel_state->commit_done);
drm_atomic_helper_commit_hw_done(state);
if (intel_state->modeset)
@@ -14559,7 +14625,9 @@ intel_atomic_commit_ready(struct i915_sw_fence *fence,
switch (notify) {
case FENCE_COMPLETE:
- if (state->base.commit_work.func)
+ if (IS_ERR(state->base.commit_work.func))
+ i915_sw_fence_commit(&state->commit_done);
+ else if (state->base.commit_work.func)
queue_work(system_unbound_wq, &state->base.commit_work);
break;
@@ -14571,16 +14639,23 @@ intel_atomic_commit_ready(struct i915_sw_fence *fence,
return NOTIFY_DONE;
}
-static void intel_atomic_track_fbs(struct drm_atomic_state *state)
+static int __i915_sw_fence_call
+intel_atomic_commit_done(struct i915_sw_fence *fence,
+ enum i915_sw_fence_notify notify)
{
- struct drm_plane_state *old_plane_state;
- struct drm_plane *plane;
- int i;
+ struct intel_atomic_state *state =
+ container_of(fence, struct intel_atomic_state, commit_done);
- for_each_plane_in_state(state, plane, old_plane_state, i)
- i915_gem_track_fb(intel_fb_obj(old_plane_state->fb),
- intel_fb_obj(plane->state->fb),
- to_intel_plane(plane)->frontbuffer_bit);
+ switch (notify) {
+ case FENCE_COMPLETE:
+ break;
+
+ case FENCE_FREE:
+ drm_atomic_state_put(&state->base);
+ break;
+ }
+
+ return NOTIFY_DONE;
}
/**
@@ -14604,15 +14679,14 @@ static int intel_atomic_commit(struct drm_device *dev,
bool nonblock)
{
struct intel_atomic_state *intel_state = to_intel_atomic_state(state);
- struct drm_i915_private *dev_priv = to_i915(dev);
- int ret = 0;
+ int ret;
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);
+ ret = drm_atomic_helper_setup_commit(state, false);
if (ret)
return ret;
@@ -14620,19 +14694,18 @@ static int intel_atomic_commit(struct drm_device *dev,
i915_sw_fence_init(&intel_state->commit_ready,
intel_atomic_commit_ready);
- ret = intel_atomic_prepare_commit(dev, state);
+ drm_atomic_state_get(state);
+ i915_sw_fence_init(&intel_state->commit_done,
+ intel_atomic_commit_done);
+
+ ret = intel_atomic_prepare_commit(state);
if (ret) {
DRM_DEBUG_ATOMIC("Preparing state failed with %i\n", ret);
+ INIT_WORK(&state->commit_work, ERR_PTR(ret));
i915_sw_fence_commit(&intel_state->commit_ready);
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);
- intel_atomic_track_fbs(state);
-
drm_atomic_state_get(state);
INIT_WORK(&state->commit_work,
nonblock ? intel_atomic_commit_work : NULL);
@@ -14954,6 +15027,7 @@ static struct drm_plane *intel_primary_plane_create(struct drm_device *dev,
if (INTEL_INFO(dev)->gen >= 4)
intel_create_rotation_property(dev, primary);
+ spin_lock_init(&primary->commit_lock);
drm_plane_helper_add(&primary->base, &intel_plane_helper_funcs);
return &primary->base;
@@ -15124,6 +15198,7 @@ static struct drm_plane *intel_cursor_plane_create(struct drm_device *dev,
if (INTEL_INFO(dev)->gen >=9)
state->scaler_id = -1;
+ spin_lock_init(&cursor->commit_lock);
drm_plane_helper_add(&cursor->base, &intel_plane_helper_funcs);
return &cursor->base;
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index d9599f960e2d..d81335bcfe97 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -363,6 +363,7 @@ struct intel_atomic_state {
struct skl_wm_values wm_results;
struct i915_sw_fence commit_ready;
+ struct i915_sw_fence commit_done;
};
struct intel_plane_state {
@@ -772,6 +773,7 @@ struct intel_plane {
uint32_t frontbuffer_bit;
struct i915_sw_fence *last_commit;
+ spinlock_t commit_lock;
/* Since we need to change the watermarks before/after
* enabling/disabling the planes, we need to store the parameters here
diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c
index 44da0287c260..5095987d905d 100644
--- a/drivers/gpu/drm/i915/intel_sprite.c
+++ b/drivers/gpu/drm/i915/intel_sprite.c
@@ -1143,6 +1143,7 @@ intel_plane_init(struct drm_device *dev, enum pipe pipe, int plane)
intel_create_rotation_property(dev, intel_plane);
+ spin_lock_init(&intel_plane->commit_lock);
drm_plane_helper_add(&intel_plane->base, &intel_plane_helper_funcs);
return 0;
--
2.9.3
More information about the Intel-gfx-trybot
mailing list