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

Rob Clark robdclark at gmail.com
Mon May 26 05:48:52 PDT 2014


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.

> - 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.

> - 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).

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.

> - 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.

>  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.

> 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.

> 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.

> - 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.

>   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.

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.

BR,
-R

>
> Cheers, 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