Skip to content

Commit 033b7a2

Browse files
committed
drm/i915: Handle pipe CRC around enabling/disabling pipe.
This will get rid of the following error: [ 74.730271] WARNING: CPU: 4 PID: 0 at drivers/gpu/drm/drm_vblank.c:614 drm_calc_vbltimestamp_from_scanoutpos+0x13e/0x2f0 [ 74.730311] Modules linked in: vgem snd_hda_codec_hdmi snd_hda_codec_realtek snd_hda_codec_generic i915 x86_pkg_temp_thermal intel_powerclamp coretemp snd_hda_intel crct10dif_pclmul snd_hda_codec crc32_pclmul snd_hwdep broadcom ghash_clmulni_intel snd_hda_core bcm_phy_lib snd_pcm tg3 lpc_ich mei_me mei prime_numbers [ 74.730353] CPU: 4 PID: 0 Comm: swapper/4 Tainted: G U 4.16.0-rc2-CI-CI_DRM_3822+ #1 [ 74.730355] Hardware name: Dell Inc. XPS 8300 /0Y2MRG, BIOS A06 10/17/2011 [ 74.730359] RIP: 0010:drm_calc_vbltimestamp_from_scanoutpos+0x13e/0x2f0 [ 74.730361] RSP: 0018:ffff88022fb03d10 EFLAGS: 00010086 [ 74.730365] RAX: ffffffffa0291d20 RBX: ffff88021a180000 RCX: 0000000000000001 [ 74.730367] RDX: ffffffff820e7db8 RSI: 0000000000000001 RDI: ffffffff82068cea [ 74.730369] RBP: ffff88022fb03d70 R08: 0000000000000000 R09: ffffffff815d26d0 [ 74.730371] R10: 0000000000000000 R11: ffffffffa0161ca0 R12: 0000000000000001 [ 74.730373] R13: ffff880212448008 R14: ffff880212448330 R15: 0000000000000000 [ 74.730376] FS: 0000000000000000(0000) GS:ffff88022fb00000(0000) knlGS:0000000000000000 [ 74.730378] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 74.730380] CR2: 000055edcbec9000 CR3: 0000000002210001 CR4: 00000000000606e0 [ 74.730382] Call Trace: [ 74.730385] <IRQ> [ 74.730397] drm_get_last_vbltimestamp+0x36/0x50 [ 74.730401] drm_update_vblank_count+0x64/0x240 [ 74.730409] drm_crtc_accurate_vblank_count+0x41/0x90 [ 74.730453] display_pipe_crc_irq_handler+0x176/0x220 [i915] [ 74.730497] i9xx_pipe_crc_irq_handler+0xfe/0x150 [i915] [ 74.730537] ironlake_irq_handler+0x618/0xa30 [i915] [ 74.730548] __handle_irq_event_percpu+0x3c/0x340 [ 74.730556] handle_irq_event_percpu+0x1b/0x50 [ 74.730561] handle_irq_event+0x2f/0x50 [ 74.730566] handle_edge_irq+0xe4/0x1b0 [ 74.730572] handle_irq+0x11/0x20 [ 74.730576] do_IRQ+0x5e/0x120 [ 74.730584] common_interrupt+0x84/0x84 [ 74.730586] </IRQ> [ 74.730591] RIP: 0010:cpuidle_enter_state+0xaa/0x350 [ 74.730593] RSP: 0018:ffffc9000008beb8 EFLAGS: 00000212 ORIG_RAX: ffffffffffffffde [ 74.730597] RAX: ffff880226b80040 RBX: 000000000031fc3e RCX: 0000000000000001 [ 74.730599] RDX: 0000000000000000 RSI: ffffffff8210fb59 RDI: ffffffff820c02e7 [ 74.730601] RBP: 0000000000000004 R08: 00000000000040af R09: 0000000000000018 [ 74.730603] R10: 0000000000000000 R11: 0000000000000000 R12: 0000000000000004 [ 74.730606] R13: ffffe8ffffd00430 R14: 0000001166120bf4 R15: ffffffff82294460 [ 74.730621] ? cpuidle_enter_state+0xa6/0x350 [ 74.730629] do_idle+0x188/0x1d0 [ 74.730636] cpu_startup_entry+0x14/0x20 [ 74.730641] start_secondary+0x129/0x160 [ 74.730646] secondary_startup_64+0xa5/0xb0 [ 74.730660] Code: e1 48 c7 c2 b8 7d 0e 82 be 01 00 00 00 48 c7 c7 ea 8c 06 82 e8 64 ec ff ff 48 8b 83 c8 07 00 00 48 83 78 28 00 0f 84 e2 fe ff ff <0f> 0b 45 31 ed e9 db fe ff ff 41 b8 d3 4d 62 10 89 c8 6a 03 41 [ 74.730754] ---[ end trace 14b1345705b68565 ]--- Changes since v1: - Don't try to apply CRC workaround when enabling pipe, it should already be enabled. Changes since v2: - Make crc functions for !DEBUGFS case inline. - Pass intel_crtc to crc functions. - Add comments to callsites. Changes since v3: - Cache selected source to pipe_crc->source. - Set pipe_crc->skipped to MIN_INT during disable to close a race condition. Changes since v4: - Handle fallout from setting pipe_crc->source in irq handler. Cc: Marta Löfstedt <[email protected]> Reported-by: Marta Löfstedt <[email protected]> Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=105185 Signed-off-by: Maarten Lankhorst <[email protected]> Link: https://patchwork.freedesktop.org/patch/msgid/[email protected] Reviewed-by: Ville Syrjälä <[email protected]>
1 parent fa73055 commit 033b7a2

File tree

4 files changed

+67
-9
lines changed

4 files changed

+67
-9
lines changed

drivers/gpu/drm/i915/i915_irq.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1627,7 +1627,7 @@ static void display_pipe_crc_irq_handler(struct drm_i915_private *dev_priv,
16271627
int head, tail;
16281628

16291629
spin_lock(&pipe_crc->lock);
1630-
if (pipe_crc->source) {
1630+
if (pipe_crc->source && !crtc->base.crc.opened) {
16311631
if (!pipe_crc->entries) {
16321632
spin_unlock(&pipe_crc->lock);
16331633
DRM_DEBUG_KMS("spurious interrupt\n");
@@ -1667,7 +1667,7 @@ static void display_pipe_crc_irq_handler(struct drm_i915_private *dev_priv,
16671667
* On GEN8+ sometimes the second CRC is bonkers as well, so
16681668
* don't trust that one either.
16691669
*/
1670-
if (pipe_crc->skipped == 0 ||
1670+
if (pipe_crc->skipped <= 0 ||
16711671
(INTEL_GEN(dev_priv) >= 8 && pipe_crc->skipped == 1)) {
16721672
pipe_crc->skipped++;
16731673
spin_unlock(&pipe_crc->lock);

drivers/gpu/drm/i915/intel_display.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12145,6 +12145,9 @@ static void intel_update_crtc(struct drm_crtc *crtc,
1214512145
if (modeset) {
1214612146
update_scanline_offset(intel_crtc);
1214712147
dev_priv->display.crtc_enable(pipe_config, state);
12148+
12149+
/* vblanks work again, re-enable pipe CRC. */
12150+
intel_crtc_enable_pipe_crc(intel_crtc);
1214812151
} else {
1214912152
intel_pre_plane_update(to_intel_crtc_state(old_crtc_state),
1215012153
pipe_config);
@@ -12325,6 +12328,13 @@ static void intel_atomic_commit_tail(struct drm_atomic_state *state)
1232512328

1232612329
if (old_crtc_state->active) {
1232712330
intel_crtc_disable_planes(crtc, old_crtc_state->plane_mask);
12331+
12332+
/*
12333+
* We need to disable pipe CRC before disabling the pipe,
12334+
* or we race against vblank off.
12335+
*/
12336+
intel_crtc_disable_pipe_crc(intel_crtc);
12337+
1232812338
dev_priv->display.crtc_disable(to_intel_crtc_state(old_crtc_state), state);
1232912339
intel_crtc->active = false;
1233012340
intel_fbc_disable(intel_crtc);

drivers/gpu/drm/i915/intel_drv.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2136,8 +2136,17 @@ int intel_pipe_crc_create(struct drm_minor *minor);
21362136
#ifdef CONFIG_DEBUG_FS
21372137
int intel_crtc_set_crc_source(struct drm_crtc *crtc, const char *source_name,
21382138
size_t *values_cnt);
2139+
void intel_crtc_disable_pipe_crc(struct intel_crtc *crtc);
2140+
void intel_crtc_enable_pipe_crc(struct intel_crtc *crtc);
21392141
#else
21402142
#define intel_crtc_set_crc_source NULL
2143+
static inline void intel_crtc_disable_pipe_crc(struct intel_crtc *crtc)
2144+
{
2145+
}
2146+
2147+
static inline void intel_crtc_enable_pipe_crc(struct intel_crtc *crtc)
2148+
{
2149+
}
21412150
#endif
21422151
extern const struct file_operations i915_display_crc_ctl_fops;
21432152
#endif /* __INTEL_DRV_H__ */

drivers/gpu/drm/i915/intel_pipe_crc.c

Lines changed: 46 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -569,7 +569,8 @@ static void hsw_pipe_A_crc_wa(struct drm_i915_private *dev_priv,
569569
static int ivb_pipe_crc_ctl_reg(struct drm_i915_private *dev_priv,
570570
enum pipe pipe,
571571
enum intel_pipe_crc_source *source,
572-
uint32_t *val)
572+
uint32_t *val,
573+
bool set_wa)
573574
{
574575
if (*source == INTEL_PIPE_CRC_SOURCE_AUTO)
575576
*source = INTEL_PIPE_CRC_SOURCE_PF;
@@ -582,7 +583,7 @@ static int ivb_pipe_crc_ctl_reg(struct drm_i915_private *dev_priv,
582583
*val = PIPE_CRC_ENABLE | PIPE_CRC_SOURCE_SPRITE_IVB;
583584
break;
584585
case INTEL_PIPE_CRC_SOURCE_PF:
585-
if ((IS_HASWELL(dev_priv) ||
586+
if (set_wa && (IS_HASWELL(dev_priv) ||
586587
IS_BROADWELL(dev_priv)) && pipe == PIPE_A)
587588
hsw_pipe_A_crc_wa(dev_priv, true);
588589

@@ -600,7 +601,8 @@ static int ivb_pipe_crc_ctl_reg(struct drm_i915_private *dev_priv,
600601

601602
static int get_new_crc_ctl_reg(struct drm_i915_private *dev_priv,
602603
enum pipe pipe,
603-
enum intel_pipe_crc_source *source, u32 *val)
604+
enum intel_pipe_crc_source *source, u32 *val,
605+
bool set_wa)
604606
{
605607
if (IS_GEN2(dev_priv))
606608
return i8xx_pipe_crc_ctl_reg(source, val);
@@ -611,7 +613,7 @@ static int get_new_crc_ctl_reg(struct drm_i915_private *dev_priv,
611613
else if (IS_GEN5(dev_priv) || IS_GEN6(dev_priv))
612614
return ilk_pipe_crc_ctl_reg(source, val);
613615
else
614-
return ivb_pipe_crc_ctl_reg(dev_priv, pipe, source, val);
616+
return ivb_pipe_crc_ctl_reg(dev_priv, pipe, source, val, set_wa);
615617
}
616618

617619
static int pipe_crc_set_source(struct drm_i915_private *dev_priv,
@@ -636,7 +638,7 @@ static int pipe_crc_set_source(struct drm_i915_private *dev_priv,
636638
return -EIO;
637639
}
638640

639-
ret = get_new_crc_ctl_reg(dev_priv, pipe, &source, &val);
641+
ret = get_new_crc_ctl_reg(dev_priv, pipe, &source, &val, true);
640642
if (ret != 0)
641643
goto out;
642644

@@ -916,7 +918,7 @@ int intel_pipe_crc_create(struct drm_minor *minor)
916918
int intel_crtc_set_crc_source(struct drm_crtc *crtc, const char *source_name,
917919
size_t *values_cnt)
918920
{
919-
struct drm_i915_private *dev_priv = crtc->dev->dev_private;
921+
struct drm_i915_private *dev_priv = to_i915(crtc->dev);
920922
struct intel_pipe_crc *pipe_crc = &dev_priv->pipe_crc[crtc->index];
921923
enum intel_display_power_domain power_domain;
922924
enum intel_pipe_crc_source source;
@@ -934,10 +936,11 @@ int intel_crtc_set_crc_source(struct drm_crtc *crtc, const char *source_name,
934936
return -EIO;
935937
}
936938

937-
ret = get_new_crc_ctl_reg(dev_priv, crtc->index, &source, &val);
939+
ret = get_new_crc_ctl_reg(dev_priv, crtc->index, &source, &val, true);
938940
if (ret != 0)
939941
goto out;
940942

943+
pipe_crc->source = source;
941944
I915_WRITE(PIPE_CRC_CTL(crtc->index), val);
942945
POSTING_READ(PIPE_CRC_CTL(crtc->index));
943946

@@ -959,3 +962,39 @@ int intel_crtc_set_crc_source(struct drm_crtc *crtc, const char *source_name,
959962

960963
return ret;
961964
}
965+
966+
void intel_crtc_enable_pipe_crc(struct intel_crtc *intel_crtc)
967+
{
968+
struct drm_crtc *crtc = &intel_crtc->base;
969+
struct drm_i915_private *dev_priv = to_i915(crtc->dev);
970+
struct intel_pipe_crc *pipe_crc = &dev_priv->pipe_crc[crtc->index];
971+
u32 val = 0;
972+
973+
if (!crtc->crc.opened)
974+
return;
975+
976+
if (get_new_crc_ctl_reg(dev_priv, crtc->index, &pipe_crc->source, &val, false) < 0)
977+
return;
978+
979+
/* Don't need pipe_crc->lock here, IRQs are not generated. */
980+
pipe_crc->skipped = 0;
981+
982+
I915_WRITE(PIPE_CRC_CTL(crtc->index), val);
983+
POSTING_READ(PIPE_CRC_CTL(crtc->index));
984+
}
985+
986+
void intel_crtc_disable_pipe_crc(struct intel_crtc *intel_crtc)
987+
{
988+
struct drm_crtc *crtc = &intel_crtc->base;
989+
struct drm_i915_private *dev_priv = to_i915(crtc->dev);
990+
struct intel_pipe_crc *pipe_crc = &dev_priv->pipe_crc[crtc->index];
991+
992+
/* Swallow crc's until we stop generating them. */
993+
spin_lock_irq(&pipe_crc->lock);
994+
pipe_crc->skipped = INT_MIN;
995+
spin_unlock_irq(&pipe_crc->lock);
996+
997+
I915_WRITE(PIPE_CRC_CTL(crtc->index), 0);
998+
POSTING_READ(PIPE_CRC_CTL(crtc->index));
999+
synchronize_irq(dev_priv->drm.irq);
1000+
}

0 commit comments

Comments
 (0)