[Intel-gfx] [PATCH 0/6] Enable PC8+ states

Daniel Vetter daniel at ffwll.ch
Wed Jun 12 18:27:21 CEST 2013


On Wed, Jun 05, 2013 at 02:21:50PM -0300, Paulo Zanoni wrote:
> From: Paulo Zanoni <paulo.r.zanoni at intel.com>
> 
> Hi
> 
> So this series is a second version of the patch I sent on April 16th. Daniel
> asked to write some patches to properly initialize the interrupts we're touching
> on the PC8+ patches, so the first 5 patches should do this.
> 
> The 6th patch is the big one enabling PC8+ and even though I still didn't
> address all of Daniel's concerns from his first review, the patch already works:
> we get into PC10 and when we get back to PC7 things are still working.

Ok, so real review now, not just function name bikeshedding ;-)

* I'd really like to see a testcase, but not per se to exercise pc8+ but
  to check that our prepare/exit code and especially the interrupt
  disabling/enabling doesn't break anything. So the overall structure of
  the test should probably be something like

  1. Put the console into raw mode (so that fbcon doesn't interfere),
  Imre's recent infrastructure patches should make this really simple.

  2. Disable all outputs with setcrtc(fb=NULL).

  3. Wait a bit until we're sure that our code has prepared for pc8+, i.e.
  all the interrupts are shut off, lcpll is disabled ...

  4. Run a subtest.

  5. Repeat.

  For subtests we need quite a pile of them I think:
  - Test getconnectors ioctl to make sure both our ->detec and ->get_modes
    callbacks have the proper aux_display runtime pm get/put calls. On a
    quick read through your patch the get/put (currently still call
    forbid/allow) in the ->get_modes hooks seem to be missing.
  - Direct i2c access from userspace. This happens both from random tools
    probing the i2c bus, but also for real uses-cases, like the ddccontrol
    tool or e.g. the Chromebook Pixie which uses gmbus as the hw i2c
    engine for the touchpad.
  - Submit a patch (this might just work when waking the gt automatically
    wakes up everything) _and_ do a blocking wait for it (this will break
    if interrupts are dead).

  It's probably good to have some correctness checks for these, e.g.
  compare the edid property while outputs are still on (so pc8+ is
  impossible) with what happens when they're off. Execbuf could be tested
  with a simple fill blt. Imo it's also important that we have a wait
  before each new subtest, to make sure we really teste everything. E.g. a
  subtest only checks EDID for one output, then waits again. Otherwise it
  could be that the working refcounting in e.g. HDMI could shadow broken
  runtime pm refcounting for dp aux if it's done right afterwards.

* spin_lock_irqsave isn't that irq-save ;-) It only blocks interrupt on
  the local cpu. See Rusty's unreliable guide to kernel locking in
  Documentation/DocBook/kernel-locking. If you don't understand what
  spin_lock_irqsave is useful for, how our current locking works or why
  the one in your patch is broken I think we should discuss this
  afterwards. Reading my irq locking review patches and comparing it to
  the locking guid could also be interesting.

  I haven't yet done the full review, but probably the safest route is to
  fully disable our interrupt handler with disable_irq while we do the
  pc8+ prepare sequence. On the exit sequence we probably don't need it.
  In any case we can reenable interrupts again with enable_irq. Maybe
  there's a possible race there (I need to review the core irq code
  first), but now I think having a tiny race there where we could miss hpd
  events is less evil than adding complex locking just for pc8+ entry.
  Even more so with the next point, which aims to unify pc8+ entry/exit
  with our existing suspend/resume code. And s/r runs in a non-reentrant
  enviroment, so if we can keep those basic assumptions that's imo
  worthwile.

* Unifying irq setup/teardown code. I'm not really happy with the
  setup/teardown code, and I think we should take a good look at trying to
  unify it with the existing driver load/unload/suspend/resume code.
  Massive register save/restore code tends to get out of sync with other
  code changes way too easily.

  Currently our irq enable sequence is:
  1. call ->irq_preinstall hook
  2. enable irq handler
  3. call ->irq_postinstall hook
  and somewhen later
  4. enable hotplug interrupt handling with our own ->hpd_irq_setup hook.

  The disabling sequence is:
  1. disable irq handler
  2. call ->irq_uninstall hook

  Now for pc8+ we want to disable/enable almost everything _but_ the hpd
  interrupts. I think with some code wrestling we should be able to do
  that with the existing functions:
  - Split the irq_unistall into two parts, irq_unistall which disables all
    interrupt sources _but_ hotplug, and a hpd_irq_teardown which disables
    hotplug, too. For that we'd need an i915_irq_unistall functions which
    first calls drm_irq_uninstall and the new ->hpd_irq_teardown hook.
    That would also allow us to unify the hotplug reenable timer teardown
    a bit.
  - Rework ->irq_postinstall and ->irq_uninstall to not frob hpd
    settings. Since we control hpd interrupts all through SDEIMR it should
    be fairly simple to disable everything but hotplug interrupts, even
    more so with the new helpers I've added in my irq locking review
    series.
  - Important is that the new ->irq_uninstall hook won't disable the
    master interrupt sources, that'd would all be moved into the
    ->hpd_irq_teardown code.

  With the pc8+ prepare sequence would look like
  1. disable irq handler
  2. call ->irq_unistall hook directly
  -> hpd interrupts are still working
  3. re-enable irq handler

  And the exit sequence would be
  1. disable irq handler
  2. call ->irq_postinstall
  3. re-enable irq handler

* As you might have guessed I see the biggest risk in us screwing up the
  interrupt handling and especially someone sneaking in while we're in
  pc8+ mode and changing the irq registers. Safe for the hotplug bits
  which might need masking due to a hotplug storm I expect all such
  changes to be bugs.

  The upshot of the above proposal now is that we can make sure that for
  all the pc8+ relevant interrupt bits calling ->irq_uninstall leaves
  behind the same state as ->irq_preinstall. So we could sprinkle massive
  amounts of WARNs into ->irq_postinstall to check that all the interupt
  registers are still in the correct state and no one changed them.

* Finally (and this part is really just an idea I'll throw out here) our
  driver setup/teardown sequences are getting pretty complicated, and
  different parts (load, s/r, pc8+, ...) will use them ever so slightly. I
  think adding an

  atomic_t dev_priv->driver_stage_ready

  bit mask would be useful. Every time a driver stage is
  loaded/setup/resumed it sets the bit, if we unload/suspend/teardown it
  gets cleared. And every driver setup stage can check at the beginning
  whether all the required pieces are present. This should help us in
  documenting the sometimes tricky ordering constraints in general.

  For this case specifically I'm thinking of 2 driver stages:
  - general_irq_ready
  - hpd_irq_ready
  Since atomic_read is as cheap as any unordered load we could sprinkle a
  few of these checks over the code, e.g. in the gmbus or dp aux irq-based
  wait code. Similar e.g. for gem in the __wait_seqno function. This
  should help a lot in debugging bugs due to missing refcounting.

For priorities I think the best approach is to start with the testcase.
I think currently you're code is missing quite a few runtime pm get/put
calls, so I'm pretty sure it'll blow up. And if it doesn't my
understanding of how pc8+ works is seriously wrong.

And once we have a solid testcase it should be much easier to move the
code piece around a bit so that we have a sane pc8+ enter/exit sequence.

Cheers, Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch



More information about the Intel-gfx mailing list