sna: Track CRTC mode changes and discard old flips

If we have a pending flip across a modeset we must be careful to drop
the stale flip_bo after the modeset.

Reported-by: Sree Harsha Totakura <freedesktop@h.totakura.in>
References: https://bugs.freedesktop.org/show_bug.cgi?id=80355#c8
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
This commit is contained in:
Chris Wilson 2014-06-22 17:53:59 +01:00
parent dae370423a
commit dca0f1c2cc
1 changed files with 18 additions and 12 deletions

View File

@ -121,6 +121,8 @@ struct sna_crtc {
uint32_t current;
} primary_rotation, sprite_rotation;
uint32_t mode_serial, flip_serial;
uint32_t last_seq, wrap_seq;
struct ust_msc swap;
@ -969,7 +971,7 @@ sna_crtc_apply(xf86CrtcPtr crtc)
DBG(("%s CRTC:%d [pipe=%d], handle=%d\n", __FUNCTION__, sna_crtc->id, sna_crtc->pipe, sna_crtc->bo->handle));
assert(config->num_output < ARRAY_SIZE(output_ids));
assert(sna->mode.num_real_output < ARRAY_SIZE(output_ids));
if (!rotation_set(sna, &sna_crtc->primary_rotation, sna_crtc->rotation)) {
ERR(("%s: set-primary-rotation failed (rotation-id=%d, rotation=%d) on CRTC:%d [pipe=%d], errno=%d\n",
@ -979,7 +981,7 @@ sna_crtc_apply(xf86CrtcPtr crtc)
DBG(("%s: CRTC:%d [pipe=%d] primary rotation set to %x\n",
__FUNCTION__, sna_crtc->id, sna_crtc->pipe, sna_crtc->rotation));
for (i = 0; i < config->num_output; i++) {
for (i = 0; i < sna->mode.num_real_output; i++) {
xf86OutputPtr output = config->output[i];
/* Make sure we mark the output as off (and save the backlight)
@ -1038,6 +1040,7 @@ sna_crtc_apply(xf86CrtcPtr crtc)
if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_SETCRTC, &arg))
return false;
sna_crtc->mode_serial++;
sna_crtc_force_outputs_on(crtc);
return true;
}
@ -1398,6 +1401,8 @@ sna_crtc_disable(xf86CrtcPtr crtc)
arg.crtc_id = sna_crtc->id;
(void)drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_SETCRTC, &arg);
sna_crtc->mode_serial++;
rotation_set(sna, &sna_crtc->primary_rotation, RR_Rotate_0);
sna_crtc_disable_shadow(sna, sna_crtc);
@ -1927,10 +1932,11 @@ sna_crtc_damage(xf86CrtcPtr crtc)
static char *outputs_for_crtc(xf86CrtcPtr crtc, char *outputs, int max)
{
struct sna *sna = to_sna(crtc->scrn);
xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
int len, i;
for (i = len = 0; i < config->num_output; i++) {
for (i = len = 0; i < sna->mode.num_real_output; i++) {
xf86OutputPtr output = config->output[i];
if (output->crtc != crtc)
@ -4563,9 +4569,9 @@ sna_crtc_flip(struct sna *sna, struct sna_crtc *crtc, struct kgem_bo *bo, int x,
DBG(("%s CRTC:%d [pipe=%d], handle=%d\n", __FUNCTION__, crtc->id, crtc->pipe, bo->handle));
assert(config->num_output < ARRAY_SIZE(output_ids));
assert(sna->mode.num_real_output < ARRAY_SIZE(output_ids));
for (i = 0; i < config->num_output; i++) {
for (i = 0; i < sna->mode.num_real_output; i++) {
xf86OutputPtr output = config->output[i];
if (output->crtc != crtc->base)
@ -4713,6 +4719,7 @@ fixup_flip:
crtc->flip_data = data;
crtc->flip_bo = kgem_bo_reference(bo);
crtc->flip_bo->active_scanout++;
crtc->flip_serial = crtc->mode_serial;
sna->mode.flip_active++;
}
@ -4919,7 +4926,7 @@ static bool sna_probe_initial_configuration(struct sna *sna)
}
/* First scan through all outputs and look for user overrides */
for (i = 0; i < config->num_output; i++) {
for (i = 0; i < sna->mode.num_real_output; i++) {
xf86OutputPtr output = config->output[i];
for (j = 0; j < ARRAY_SIZE(user_overrides); j++) {
@ -4965,14 +4972,11 @@ static bool sna_probe_initial_configuration(struct sna *sna)
}
/* Reconstruct outputs pointing to active CRTC */
for (i = 0; i < config->num_output; i++) {
for (i = 0; i < sna->mode.num_real_output; i++) {
xf86OutputPtr output = config->output[i];
uint32_t crtc_id;
if (to_sna_output(output) == NULL) {
assert(output->crtc == NULL);
continue;
}
assert(to_sna_output(output));
crtc_id = (uintptr_t)output->crtc;
output->crtc = NULL;
@ -6287,6 +6291,7 @@ disable1:
sna_crtc->flip_handler = shadow_flip_handler;
sna_crtc->flip_bo = bo;
sna_crtc->flip_bo->active_scanout++;
sna_crtc->flip_serial = sna_crtc->mode_serial;
sna_crtc->shadow_bo = kgem_bo_reference(sna_crtc->bo);
} else {
@ -6414,6 +6419,7 @@ fixup_flip:
crtc->flip_handler = shadow_flip_handler;
crtc->flip_bo = kgem_bo_reference(flip_bo);
crtc->flip_bo->active_scanout++;
crtc->flip_serial = crtc->mode_serial;
{
struct drm_i915_gem_busy busy = { flip_bo->handle };
@ -6483,7 +6489,7 @@ void sna_mode_wakeup(struct sna *sna)
assert(crtc->flip_bo->active_scanout);
assert(crtc->flip_bo->refcnt >= crtc->flip_bo->active_scanout);
if (crtc->bo) {
if (crtc->flip_serial == crtc->mode_serial) {
DBG(("%s: removing handle=%d from scanout, installing handle=%d\n",
__FUNCTION__, crtc->bo->handle, crtc->flip_bo->handle));
assert(crtc->bo->active_scanout);