Skip to content
  • Paulo Zanoni's avatar
    drm/i915: also disable south interrupts when handling them · 44498aea
    Paulo Zanoni authored
    From the docs:
    
      "IIR can queue up to two interrupt events. When the IIR is cleared,
      it will set itself again after one clock if a second event was
      stored."
    
      "Only the rising edge of the PCH Display interrupt will cause the
      North Display IIR (DEIIR) PCH Display Interrupt even bit to be set,
      so all PCH Display Interrupts, including back to back interrupts,
      must be cleared before a new PCH Display interrupt can cause DEIIR
      to be set".
    
    The current code works fine because we don't get many interrupts, but
    if we enable the PCH FIFO underrun interrupts we'll start getting so
    many interrupts that at some point new PCH interrupts won't cause
    DEIIR to be set.
    
    The initial implementation I tried was to turn the code that checks
    SDEIIR into a loop, but we can still get interrupts even after the
    loop is done (and before the irq handler finishes), so we have to
    either disable the interrupts or mask them. In the end I concluded
    that just disabling the PCH interrupts is enough, you don't even need
    the loop, so this is what this patch implements. I've tested it and it
    passes the 2 "PCH FIFO underrun interrupt storms" I can reproduce:
    the "ironlake_crtc_disable" case and the "wrong watermarks" case.
    
    In other words, here's how to reproduce the problem fixed by this
    patch:
      1 - Enable PCH FIFO underrun interrupts (SERR_INT on SNB+)
      2 - Boot the machine
      3 - While booting we'll get tons of PCH FIFO underrun interrupts
      4 - Plug a new monitor
      5 - Run xrandr, notice it won't detect the new monitor
      6 - Read SDEIIR and notice it's not 0 while DEIIR is 0
    
    Q: Can't we just clear DEIIR before SDEIIR?
    A: It doesn't work. SDEIIR has to be completely cleared (including the
    interrupts stored on its back queue) before it can flip DEIIR's bit to
    1 again, and even while you're clearing it you'll be getting more and
    more interrupts.
    
    Q: Why does it work by just disabling+enabling the south interrupts?
    A: Because when we re-enable them, if there's something on the SDEIIR
    register (maybe an interrupt stored on the queue), the re-enabling
    will make DEIIR's bit flip to 1, and since we'll already have
    interrupts enabled we'll get another interrupt, then run our irq
    handler again to process the "back" interrupts.
    
    v2: Even bigger commit message, added code comments.
    
    Note that this fixes missed dp aux irqs which have been reported for
    3.9-rc1. This regression has been introduced by switching to
    irq-driven dp aux transactions with
    
    commit 9ee32fea
    Author: Daniel Vetter <daniel.vetter@ffwll.ch>
    Date:   Sat Dec 1 13:53:48 2012 +0100
    
        drm/i915: irq-drive the dp aux communication
    
    References: http://www.mail-archive.com/intel-gfx@lists.freedesktop.org/msg18588.html
    References: https://lkml.org/lkml/2013/2/26/769
    
    
    Tested-by: default avatarImre Deak <imre.deak@intel.com>
    Reported-by: default avatarSedat Dilek <sedat.dilek@gmail.com>
    Reported-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
    Signed-off-by: default avatarPaulo Zanoni <paulo.r.zanoni@intel.com>
    [danvet: Pimp commit message with references for the dp aux irq
    timeout regression this fixes.]
    Signed-off-by: default avatarDaniel Vetter <daniel.vetter@ffwll.ch>
    44498aea