[PATCH 00/17] prepare for atomic/nuclear modeset/pageflip

Rob Clark robdclark at gmail.com
Mon May 26 09:12:38 PDT 2014


On Mon, May 26, 2014 at 11:24 AM, Daniel Vetter <daniel at ffwll.ch> wrote:
> On Mon, May 26, 2014 at 08:48:52AM -0400, Rob Clark wrote:
>> On Mon, May 26, 2014 at 6:40 AM, Daniel Vetter <daniel at ffwll.ch> wrote:
>> > On Sat, May 24, 2014 at 02:30:09PM -0400, Rob Clark wrote:
>> >> One more time, with feeling..
>> >>
>> >> Previous revision of series:
>> >> http://lists.freedesktop.org/archives/dri-devel/2014-March/055806.html
>> >>
>> >> And if you prefer, in git form:
>> >> http://cgit.freedesktop.org/~robclark/linux/log/?h=cold-fusion
>> >> git://people.freedesktop.org/~robclark/linux cold-fusion
>> >>
>> >> This series does not include the actual atomic ioctl, but it does
>> >> include all the needed infrastructure changes.
>> >>
>> >> Compared to previous revision, I've split out drm_modeset_acquire_ctx
>> >> from drm_atomic_state, so that we can ww acquire mode_config and crtc
>> >> locks outside of atomic transactions.  (Which keeps lockdep happy wrt.
>> >> drm_modeset_lock_all().)  I also got to the point in juggling things
>> >> around where I wanted to let the compiler type checking do it's job,
>> >> so 's/void *state/struct drm_atomic_state *state/g'.
>> >>
>> >> At this point, I've tested this on i915 (few different generation
>> >> laptops), radeon, and msm.  And of course w/ ww debug (deadlock in-
>> >> jection) enabled.  So I think all the locking related paths should
>> >> be covered.
>> >>
>> >> I believe Thierry has tested a slighly older revision on tegra.  I
>> >> would of course appreciate more testing on other drivers for which I
>> >> don't have the hw.  But I think it is pretty much ready to go.  I do
>> >> still owe some docs updates, I will send some patches for that in
>> >> the near future, but didn't want to hold up giving others a chance
>> >> to start banging on this.
>> >
>> > Ok, I've done a fairly cursory look at this only and tried to concentrate
>> > on grasping the high-level details. Patches contain a bunch of comments on
>> > the details, but here is the big stuff.
>> >
>> > First things first there's a bunch of prep work and refactoring sprinkled
>> > throughout the series. Imo we should pick those out and rebase them on top
>> > of drm-next asap to get them in before the actual interfaces. I hope I've
>> > catched them all and commented everywhere about what imo is still missing
>> > for merging. With that out of the way the real atomic review below.
>> >
>> > I like the overall design. It will be a royal pain to convert i915 over to
>> > this since thus far we've simply tucked away the staged state into
>> > obj->new_foo pointers. Which means we get to change the entire driver
>> > again ;-)
>> >
>> > But I think the interfaces to driver and overall api design need some good
>> > polish:
>> >
>> > - Imo way too much is done in driver callbacks, which then again call
>> >   helpers. Parsing of the core properties for plane/crtcs should be done
>> >   in the core imo. This way drivers only need to register ->set_prop
>> >   callbacks if there's a driver-specific property they support.
>>
>> Pretty universally, the approach I took was to provide default fxns
>> (for ->atomic_xyz(), ->set_property(), ->create_state(), etc), and let
>> drivers wrap them as needed.  We might need to tweak
>> drm_atomic_begin() a bit for the first driver that needs to wrap
>> drm_atomic_state, but I guess we can tackle that as the need arises.
>>
>> > - Imo those obj->set_prop callbacks should take the object-specific
>> >   drm_obj_state object, not the global atomic state structure. Will lead
>> >   to _much_ less lookup code duplicated all over the place. If we then
>> >   also add a state->obj pointer we could also ditch that parameter. Ofc
>> >   obj would be specific to the state at hand.
>>
>> The problem is if those callbacks need to take other driver shared
>> locks.. that plus initially I was trying to keep state as opaque as
>> possible (in case sooner or later i915 decided to re-implement :-P)
>>
>> Eventually I decided keeping state opaque was too much pita, and that
>> if driver wanted to do something different, it should instead
>> subclass.  So I guess these days they could chase [pc]state->state to
>> get back at the global state.
>
> I don't think keeping state opaque is a feature. Imo we _want_ to have
> some common structures to track the common set of properties, for
> otherwise insanity will rule. Drivers can add whatever they whish by
> subclassing the existing state structs and add whatever they need to track
> their state. I don't have any intentions to implement something
> newfangled/different for i915, but instead want to port our current
> infrastructure over to this.
>
> Having clear prepare&check (we call it compute) and commit semantics is
> imo the right way to do kms. Think of i915 as the poc vehicle that gets to
> pay the bill of rewriting the driver twice.
>
> So I'm advocating to move even further avoid from void* everywhere than
> you've moved already.
>
> Wrt helpers I think at least for modeset operations we can pimp the crtc
> helpers and mostly reuse the hooks we already have, maybe augmented with
> per-object ->check hooks. But for nuclear pageflips I really don't see a
> chance but a single driver-gloabl ->commit (and fwiw check) hook. Maybe
> per-crtc at best, but that will already run into planes changing crtcs.

The per-object hooks will work with at least three display controller
blocks that I know of (two in msm, and omapdrm), so I guess it is not
*that* uncommon.

We'll need to split up an existing fxn or two so that other drivers
can do an all-at-once commit more easily.  That seems like a fairly
small tweak, and I think it would be ok to merge along w/ i915 atomic
support.

>> > - One downside of that is that drivers won't be able to interfere the
>> >   allocation step any more. I think we'd need an additional
>> >   ->alloc_atomic_state call so that drivers can still easily subclass some
>> >   objects with their own type.
>>
>> the ->create_state() is already split out as a vfunc for planes and
>> crtcs.  Which I think should be enough to cover most of what drivers
>> need.  If driver needs to subclass global state too, then we need to
>> split up drm_atomic_begin(), but I guess that should be a relatively
>> small change that we can make when it becomes needed.
>
> I guess i915 will need it, to keep track of shared resources like plls.
> Atm we carry them around in dev_priv, without any precompute/commit
> semantics. Still something that needs to be fixed ...

it would seem tempting to put in i915_atomic_state, but then how does
it work with multiple parallel but independent atomic updates, or
should that not be allowed?

> Wrt ->create_state: I simply missed that in all the patches. But if you
> have that I don't quite understand why the various ->set_property
> callbacks have checks whether the object-specific state exists already and
> allocate it if not through the get_plane_state and similar functions. Imo
> that kind of stuff should be handled in the core. Error handling code is
> really hard to get correct ime, and we depend upon it's correctness here
> (at least with the current locking scheme) for ww mutexes to work.

Well, the current approach gave the driver more flexibility about what
locks to grab, etc.. although I suppose some of this might be less
needed now with primary planes.  Formerly I had to fwd some properties
from crtc to my own internal primary plane, which required the
flexibility that the current approach gives.

>> > - There's imo a bit a confusion between what's helper and what's driver
>> >   api. My big gripe here is with the set_prop stuff which imo really
>> >   should be core and not helpers. The default ->commit/check
>> >   implementations otoh should be more clearly delineated as helper
>> >   implementations that drivers can/should overwrite. I think we should
>> >   split drm_atomic.c into drm_atomic.c (with the official pieces) and
>> >   drm_atomic_helper.c (with the suggested standard/transitional
>> >   implemenations for commit/check). Helper functions should have the
>> >   drm_atomic_helper_ prefix.
>>
>> Hmm, I think nearly *everything* could be overridden.. maybe it could
>> be more clear what to override vs outright replace.  But otoh I'm not
>> quite sure yet what drivers will need to override (other than some
>> obvious ones, which are already broken out into vfuncs, like
>> {plane,crtc}->create_state() to handle driver custom properties).
>
> Like I've said above we should imo try to unify the world a bit more
> again. And for the state tracking that should be possible, so I don't see
> a need to hand drivers too much rope.
>
> The check/commit stuff otoh should be fully overrideable, since i915 will
> need that.
>
>> So I expect some tweaks as other drivers start adding native atomic
>> support.  I basically added what I needed for msm, and what I thought
>> was pretty safe bet that other drivers would need.  This at least
>> gives us something other drivers could start trying to use.  Then see
>> what is missing and add it as we go.  At least that was my line of
>> thinking.
>
> Like I've said I don't think there's much value beyong making crtc helpers
> atomic capable for modeset changes. Atomic pageflips pretty much need
> driver-specific magic (less so if there's a "GO" bit like on sane
> hardware).

right, there is a very tiny bit of driver magic in msm_atomic_commit()..

anyways, I don't disagree that we probably need to add something for
some drivers to be able to hook in to ->atomic_commit() after locking
magic but before loop over planes/crtcs.  I think that would simply be
addition to the api, ie. new fxn ptr a driver could populate.  I
wouldn't need it for msm.

>> > - I also think we should split the vfuncs like we do with the crtc
>> >   helpers. Imo the core interface should just be an ->alloc_state and
>> >   ->set_prop on all kms objects, plus a global ->prep/check/commit at the
>> >   driver level. The object-specific ->check/commit hooks otoh should be
>> >   part of the atomic helper library and in some separate
>> >   atomic_helper_funcs structure.
>>
>> this is in fact the way it is, although 'struct drm_atomic_funcs'
>> maybe should have "helper" in the name.
>
> Yeah, I'm mostly just asking for sprinkling helper all over the stuff that
> clearly is helper code. And moving everything else into the core and
> making it non-overrideable.
>
>> >  Imo we could either extend the sturcture
>> >   used by the crtc helpers (hackish imo) or change the type of that to
>> >   make it clear it's for the crtc helpers and add a new pointer for atomic
>> >   helpers. E.g. in i915 I expect that we'll implement our very own
>> >   ->check/commit hooks using our own compute_config infrastructure. Maybe
>> >   we could switch to the ->check hooks of the atomic helper eventually,
>> >   but that will be a lot of work. And in any case we won't ever switch to
>> >   the ->commit hook as you have it in your helpers since for truly atomic
>> >   flips/modesets we need to interleave all the updates of all objects in
>> >   various phases.
>>
>> not sure if it would work for you, but in msm I have a per-crtc "don't
>> actually commit yet" bit, which gets set for each crtc involved in
>> atomic update.  Although in my case it is mainly a matter of not
>> touching the "GO" bits until everything is setup..
>>
>> If not, I guess it shouldn't be a big deal to, for example, split up
>> atomic_commit() into part that did the locking dance and then call
>> vfunc ->atomic_apply_state() or something like that.
>>
>> Basically figure out where you need to hook in for i915 as you add
>> native atomic support.  By the time you and maybe one or two other
>> drivers have added atomic support we should have it pretty well nailed
>> down.  But until then, there might be some small adjustments
>> here/there.
>
> For modeset changes we need to munge everything through the full state
> precompute and then commit to hw machinery. Not yet fully there (since the
> shared dpll stuff doesn't work yet). For nuclear pageflips we're only just
> starting to merge all of Ville's infrastructure, but will probably be the
> same. So imo the only hand-off point between the core and drm is the
> single, global ->commit. ->check would be the identical code, except for
> the final commit.
>
> All the ->set_prop callbacks would do nothing else but store data into
> structures.

I suspect I'll want to see which core properties change eventually..
when I have a chance to implement YUV and scaling, I'd want to flag
that scaling/csc coefficients need updating, etc.

It doesn't seem unreasonable to pass plane/crtc state rather than
global state.  (Although we would need connector_state.. which is
something I've not found a good use for yet.)  But other than that,
I'd kinda like to leave the ->set_property() as it is.

BR,
-R

>
>> > The patches are also rather big, which makes them a bit a pain to review.
>> > Matt's approach for the primary planes was much easier:
>> > 1) Add the new core interfaces for the new world.
>> > 2) Implement helpers for drivers to transition and convert drivers.
>> > 3) Implement ioctls using the new driver interfaces.
>>
>> not so far different from what I did.  Although I suppose I could have
>> split up adding atomic support for plane/crtc vs converting over
>> existing ioctls to use it.  Not sure if it is worth doing at this
>> stage or not.  Not really sure that it would help in sorting out what
>> is helper vs not.
>
> It's mostly for reviewing - silly me got lost countless times in your
> patches.
>
>> > That approach would also help a lot in figuring out what's helper code and
>> > so optional, and what's core stuff.
>> >
>> > The other big problem I see still is with the locking:
>> >
>> > - Imo switching mode_config.mutex to a ww_mutex won't work. I know that
>> >   the magic rules of w/w locking are _really_ tempting. But I don't think
>> >   it will actually solve anything and instead only cause havoc.
>>
>> are you actually getting lockdep splats?  If so pls send them my way
>> and I'll have a look.
>>
>> In non-atomic cases we are still using these as bare mutex's (other
>> than the one special case where we needed nested_lock before).  So I
>> think if it worked before, it should continue to work.
>
> Didn't run it, but pretty sure. I think the other mail conversation
> cleared that up - mixing w/w nesting and static nesting just don't work:
> Static nesting means locks are filed into different (static) groups, w/w
> nesting means you have one single locking class, but ordered dynamically
> with the backoff magic.
>
>> > - I think we need ww mutexes for crtcs, but they will be fairly useless
>> >   without ww mutexes on plane. Not for i915, but for all those drivers
>> >   which can switch planes around between different crtcs. Imo we should do
>> >   this as a first step (before getting all the atomic interfaces in), and
>> >   pimp the set_plane locking a bit already like I've described in some
>> >   mail.
>> >
>> > - There's a pile of state that's currently not really protected by
>> >   anything in your patches. One piece is all the obj->state properties.
>> >   Another one is state detected at runtime like e.g. whether a hdmi sink
>> >   supports audio or what kind of link bw parameters a dp sink supports.
>> >   Thus far this was all protected by mode_config.mutex, but we can't take
>> >   this one in the generic atomic ioctls for pretty obvious reasons.
>>
>> we are still taking mode_config.mutex in places where we did before
>> (setcrtc, setplane, etc).  So it shouldn't be a problem *yet*.
>>
>> Runtime internal params about hw state, as opposed to things userspace
>> is asking for, should perhaps not be in obj->state?  Or maybe I'm
>> misunderstanding you.
>
> Afaict we copy obj->state and ->set_prop (at least in i915) also looks at
> a bunch of other connector state. And at that point we don't hold
> mode_config.mutex, and I couldn't spot anything else. Thus far all the
> ->set_prop stuff _did_ hold mode_config.mutex.
>
>> >   I think we need a new lock here, e.g. dev->mode_config.state_lock. It's
>> >   going to be painful, since we need to roll this out over _all_ driver
>> >   callbacks which can change the meaning of some property. E.g. all the
>> >   ->detect callbacks in i915. The important part is that no one is allowed
>> >   to do any costly operations why holding this lock (i.e. anything like
>> >   reading EDIDs or doing load-detect), it is only for updating/reading
>> >   this state.
>> >
>> > - To avoid nasties with locking inversion between the plain
>> >   mode_config.mutex, the state_mutex and the various ww mutexes we need to
>> >   rather completely rework the locking sequence for atomic updates
>> >   compared to what you have. Since in the driver's detect callbacks we
>> >   first grab the mode_config.mutex and then potentiall ww mutexes (only
>> >   i915) and maybe also the state_mutex (for updating autodetected
>> >   properties). But for atomic updates we first need to grab the
>> >   state_mutex (so that we can get at the current state) and then ww
>> >   mutexes and the mode_config.mutex. And for the later we're not even good
>> >   at predicting the order we want to acquire them.
>>
>> so I think I need to understand the call sequence for the detect thing
>> in i915, since atm I'm not quite sure what the problem is, and why it
>> worked before..
>>
>> >   Stage 1: Create the new state
>> >   We grab _just_ the mode_config.state_mutex and allocate all the state
>> >   objects. This will allow us to grab a copy of the current state of
>> >   everything without races or inconsistencies.
>> >
>> >   As a consequence ->set_prop hooks may not touch anything outside of the
>> >   date/state protected by the state_mutex.
>> >
>> >   Stage 2: check/commit stage
>> >   We drop the state_lock since it would nest the wrong way round again
>> >   with mode_config.mutex. We should have a complete copy of all state
>> >   already, and if something races against us (2nd ioctl or a output probe
>> >   call) we don't really care.
>> >
>> >   Only then will the check/commit hooks grab all the locks. For the
>> >   mode_config.mutex we could add a bit to the global state the we need it
>> >   (e.g. when the connector->crtc links change or for some other
>> >   driver-private need).
>> >
>> >   That only leaves races with a 2nd concurrent atomic modeset ioctl. Which
>> >   can be avoided by grabbing yet another lock, which we drop after the
>> >   driver has acquired all real locks. For that we could mandate the
>> >   ->check callback and require that it grabs all ww mutexes plus the
>> >   mode_config.mutex.
>> >
>> > For implementing this madness (if we agree it's the right approach) we can
>> > go step-by-step:
>> > - Convert crtc->mutex to a ww mutex.
>> > - Add plane ww mutexes, make set_plane locking more fine-grained.
>> > - Add the mode_config.state_lock, roll it out across all driver's ->detect
>> >   callbacks and add it to modeset_lock_all (so that set_prop calls dtrt).
>> > - Use all this correctly in the atomic stuff.
>> >
>> > Ok, that's the two big comments on this work from my side. Now reality
>> > check: How much off the mark am I?
>>
>> well, I think in summary, it is (a) might need to split few things up
>> or re-arrange things slightly as i915 and other drivers start adding
>> native atomic support.. but this doesn't scare me too much, and I
>> think we can take it as we go.
>
> The problem I see here is massive churn over drivers. If we try to make
> set_prop hooks and similar stuff optional we'd avoid that, and would
> actually gain flexibility with fixing the interfaces down the road. If we
> enforce default callbacks for everyone that will only bloat diffs.
>
>> And (b) possible locking fun.. this I think actually does need to be
>> sorted first.  Although I'm not quite sure I understand why it is
>> actually a problem.
>
> Plan B for this might be to go full bore on ww mutexes and also protect
> connectors with them. Then atomic updates would never have a need for
> mode_config.mutex, and the role of that lock would be restricted to some
> detect fun. Less complicated locking scheme, but even more code to audit.
> -Daniel
> --
> Daniel Vetter
> Software Engineer, Intel Corporation
> +41 (0) 79 365 57 48 - http://blog.ffwll.ch


More information about the dri-devel mailing list