[PATCH 00/17] prepare for atomic/nuclear modeset/pageflip
Daniel Vetter
daniel at ffwll.ch
Mon May 26 03:40:34 PDT 2014
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.
- 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.
- 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.
- 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.
- 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. 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.
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.
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.
- 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.
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.
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?
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