On Sat, Mar 07, 2020 at 08:50:44PM -0400, Jon Whalen wrote:
> Hi there,
> 
> I also receive these errors as well as hangs on an old Dell Inspiron
> 1525 with OpenBSD, several releases of Ubuntu Linux, and NetBSD 9.0.
> My unqualified assumption is that it's an Intel i915 driver issue and
> not an actual OpenBSD issue. I don't know anything about computer
> programming, but given the errors, I wonder if it could be narrowed
> down to the drm_irq.c, drm_vblank.c, and/or intel_fifo_underrun.c
> files in the Intel driver? There are differences between the current
> Linux and OpenBSD source trees, but I lack the skills, expertise, and
> brain power to begin troubleshooting this. The main differences appear
> to have something to do with spinlocks and mutexes, but again, this is
> beyond my abilities.
> 
> OpenBSD became affected after 6.6 development began (6.5 is not
> affected). Probably irrelevant, but not all Linux distributions are
> affected; Kubuntu and Alpine are not, and neither is the latest Ubuntu
> 20.04 development release.
> 
> NetBSD 9.0 repeated the following errors upon boot and is what led me
> to my assumption above:
> [4.6926206] warning:
> /usr/src/sys/external/bsd/drm2/dist/drm/drm_irq.c:1510 vblank wait
> timed out on crtc 0
> [4.7526574] kern error:
> [drm:(/usr/src/sys/external/bsd/drm2/dist/drm/i915/intel_fifo_underrun.c:363)intel_cpu_fifo_underrun_irq_handler]
> *ERROR* CPU pipe A FIFO underrun
> 
> Booting OpenBSD with inteldrm enabled, there is a delay of
> approximately 30 seconds when inteldrm is "probed" after root is
> mounted, which is also when the [drm] errors begin to appear. The boot
> process continues normally after the hang.
> 
> If xenodm is configured to start it takes about 60 seconds for it to
> load and become usable.
> 
> After entering credentials into xenodm, cwm takes approximately 30
> seconds to become usable and xconsole starts repeating the same [drm]
> errors. Things seem to work fine after this, though the errors
> continue to litter /var/log/messages.
> 
> Resuming from a suspend, the system hangs for ~30s.
> 
> None of this occurs if inteldrm is disabled.
> 
> On Linux, adding the following line to the grub conf eliminated the
> errors and hangs:
> 
> GRUB_CMDLINE_LINUX_DEFAULT="video=SVIDEO-1:d"
> 
> Is it possible to pass similar Linux grub parameters to boot on
> OpenBSD via boot.conf? If there is a way, could this be the "easiest"
> solution?
> 
> Sendbug text below, with -current as of March 7, 2020.
> 
> This message refers to:
> https://marc.info/?t=158075190100001&r=1&w=2

https://bugs.freedesktop.org/show_bug.cgi?id=93782

This appears to have been fixed in linux 5.1 in commit
32db0b6501d97b09e92e70caefc74fa35aa9a8d6 which was marked as being for
stable but did not appear in the stable branches likely due it it not
applying cleanly (ed20151a7699bb2c77eba3610199789a126940c4 did land in
the 4.19 branch so we already have that).

Here is a backport of 32db0b6501d97b09e92e70caefc74fa35aa9a8d6 to our
4.19 tree.

drm/i915: Don't try to use the hardware frame counter with i965gm TV output

Index: sys/dev/pci/drm/i915/i915_irq.c
===================================================================
RCS file: /cvs/src/sys/dev/pci/drm/i915/i915_irq.c,v
retrieving revision 1.33
diff -u -p -r1.33 i915_irq.c
--- sys/dev/pci/drm/i915/i915_irq.c     14 Apr 2019 10:14:51 -0000      1.33
+++ sys/dev/pci/drm/i915/i915_irq.c     8 Mar 2020 12:46:04 -0000
@@ -822,11 +822,26 @@ static void i915_enable_asle_pipestat(st
 static u32 i915_get_vblank_counter(struct drm_device *dev, unsigned int pipe)
 {
        struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
+       const struct drm_display_mode *mode = &vblank->hwmode;
        i915_reg_t high_frame, low_frame;
        u32 high1, high2, low, pixel, vbl_start, hsync_start, htotal;
-       const struct drm_display_mode *mode = &dev->vblank[pipe].hwmode;
        unsigned long irqflags;
 
+       /*
+        * On i965gm TV output the frame counter only works up to
+        * the point when we enable the TV encoder. After that the
+        * frame counter ceases to work and reads zero. We need a
+        * vblank wait before enabling the TV encoder and so we
+        * have to enable vblank interrupts while the frame counter
+        * is still in a working state. However the core vblank code
+        * does not like us returning non-zero frame counter values
+        * when we've told it that we don't have a working frame
+        * counter. Thus we must stop non-zero values leaking out.
+        */
+       if (!vblank->max_vblank_count)
+               return 0;
+
        htotal = mode->crtc_htotal;
        hsync_start = mode->crtc_hsync_start;
        vbl_start = mode->crtc_vblank_start;
@@ -4803,16 +4818,10 @@ void intel_irq_init(struct drm_i915_priv
        if (INTEL_GEN(dev_priv) >= 8)
                rps->pm_intrmsk_mbz |= GEN8_PMINTR_DISABLE_REDIRECT_TO_GUC;
 
-       if (IS_GEN2(dev_priv)) {
-               /* Gen2 doesn't have a hardware frame counter */
-               dev->max_vblank_count = 0;
-       } else if (IS_G4X(dev_priv) || INTEL_GEN(dev_priv) >= 5) {
-               dev->max_vblank_count = 0xffffffff; /* full 32 bit counter */
+       if (INTEL_GEN(dev_priv) >= 5 || IS_G4X(dev_priv))
                dev->driver->get_vblank_counter = g4x_get_vblank_counter;
-       } else {
+       else if (INTEL_GEN(dev_priv) >= 3)
                dev->driver->get_vblank_counter = i915_get_vblank_counter;
-               dev->max_vblank_count = 0xffffff; /* only 24 bits of frame 
count */
-       }
 
        /*
         * Opt out of the vblank disable timer on everything except gen2.
Index: sys/dev/pci/drm/i915/intel_display.c
===================================================================
RCS file: /cvs/src/sys/dev/pci/drm/i915/intel_display.c,v
retrieving revision 1.66
diff -u -p -r1.66 intel_display.c
--- sys/dev/pci/drm/i915/intel_display.c        16 Sep 2019 15:16:47 -0000      
1.66
+++ sys/dev/pci/drm/i915/intel_display.c        8 Mar 2020 12:46:04 -0000
@@ -1816,6 +1816,35 @@ enum pipe intel_crtc_pch_transcoder(stru
                return crtc->pipe;
 }
 
+static u32 intel_crtc_max_vblank_count(const struct intel_crtc_state 
*crtc_state)
+{
+       struct drm_i915_private *dev_priv = to_i915(crtc_state->base.crtc->dev);
+
+       /*
+        * On i965gm the hardware frame counter reads
+        * zero when the TV encoder is enabled :(
+        */
+       if (IS_I965GM(dev_priv) &&
+           (crtc_state->output_types & BIT(INTEL_OUTPUT_TVOUT)))
+               return 0;
+
+       if (INTEL_GEN(dev_priv) >= 5 || IS_G4X(dev_priv))
+               return 0xffffffff; /* full 32 bit counter */
+       else if (INTEL_GEN(dev_priv) >= 3)
+               return 0xffffff; /* only 24 bits of frame count */
+       else
+               return 0; /* Gen2 doesn't have a hardware frame counter */
+}
+
+static void intel_crtc_vblank_on(const struct intel_crtc_state *crtc_state)
+{
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
+
+       drm_crtc_set_max_vblank_count(&crtc->base,
+                                     intel_crtc_max_vblank_count(crtc_state));
+       drm_crtc_vblank_on(&crtc->base);
+}
+
 static void intel_enable_pipe(const struct intel_crtc_state *new_crtc_state)
 {
        struct intel_crtc *crtc = to_intel_crtc(new_crtc_state->base.crtc);
@@ -1868,7 +1897,7 @@ static void intel_enable_pipe(const stru
         * when it's derived from the timestamps. So let's wait for the
         * pipe to start properly before we call drm_crtc_vblank_on()
         */
-       if (dev_priv->drm.max_vblank_count == 0)
+       if (intel_crtc_max_vblank_count(new_crtc_state) == 0)
                intel_wait_for_pipe_scanline_moving(crtc);
 }
 
@@ -5600,7 +5629,7 @@ static void ironlake_crtc_enable(struct 
                ironlake_pch_enable(old_intel_state, pipe_config);
 
        assert_vblank_disabled(crtc);
-       drm_crtc_vblank_on(crtc);
+       intel_crtc_vblank_on(pipe_config);
 
        intel_encoders_enable(crtc, pipe_config, old_state);
 
@@ -5758,7 +5787,7 @@ static void haswell_crtc_enable(struct i
                intel_ddi_set_vc_payload_alloc(pipe_config, true);
 
        assert_vblank_disabled(crtc);
-       drm_crtc_vblank_on(crtc);
+       intel_crtc_vblank_on(pipe_config);
 
        intel_encoders_enable(crtc, pipe_config, old_state);
 
@@ -6064,7 +6093,7 @@ static void valleyview_crtc_enable(struc
        intel_enable_pipe(pipe_config);
 
        assert_vblank_disabled(crtc);
-       drm_crtc_vblank_on(crtc);
+       intel_crtc_vblank_on(pipe_config);
 
        intel_encoders_enable(crtc, pipe_config, old_state);
 }
@@ -6123,7 +6152,7 @@ static void i9xx_crtc_enable(struct inte
        intel_enable_pipe(pipe_config);
 
        assert_vblank_disabled(crtc);
-       drm_crtc_vblank_on(crtc);
+       intel_crtc_vblank_on(pipe_config);
 
        intel_encoders_enable(crtc, pipe_config, old_state);
 }
@@ -12414,8 +12443,9 @@ static int intel_atomic_prepare_commit(s
 u32 intel_crtc_get_vblank_counter(struct intel_crtc *crtc)
 {
        struct drm_device *dev = crtc->base.dev;
+       struct drm_vblank_crtc *vblank = 
&dev->vblank[drm_crtc_index(&crtc->base)];
 
-       if (!dev->max_vblank_count)
+       if (!vblank->max_vblank_count)
                return (u32)drm_crtc_accurate_vblank_count(&crtc->base);
 
        return dev->driver->get_vblank_counter(dev, crtc->pipe);
@@ -15846,10 +15876,13 @@ intel_modeset_setup_hw_state(struct drm_
         * waits, so we need vblank interrupts restored beforehand.
         */
        for_each_intel_crtc(&dev_priv->drm, crtc) {
+               struct intel_crtc_state * crtc_state =
+                       to_intel_crtc_state(crtc->base.state);
+
                drm_crtc_vblank_reset(&crtc->base);
 
-               if (crtc->active)
-                       drm_crtc_vblank_on(&crtc->base);
+               if (crtc_state->base.active)
+                       intel_crtc_vblank_on(crtc_state);
        }
 
        intel_sanitize_plane_mapping(dev_priv);

Reply via email to