diff options
author | Daniel Vetter <daniel.vetter@ffwll.ch> | 2016-09-30 06:04:56 -0400 |
---|---|---|
committer | Daniel Vetter <daniel.vetter@ffwll.ch> | 2016-10-04 02:23:15 -0400 |
commit | 61802130d85fdaf9646340bf1cc64b3e06d0b19c (patch) | |
tree | 85202da72b57a058e2708c7314e3f66b4fb523a3 | |
parent | 58f0f9f75c1b94dabbfc3daa333a4e68536b0a42 (diff) |
drm: Document caveats around atomic event handling
It's not that obvious how a driver can all race the atomic commit with
handling the completion event. And there's unfortunately a pile of
drivers with rather bad event handling which misdirect people into the
wrong direction.
Try to remedy this by documenting everything better.
v2: Type fixes Alex spotted.
v3: More typos Alex spotted.
Cc: Andrzej Hajda <a.hajda@samsung.com>
Cc: Alex Deucher <alexdeucher@gmail.com>
Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1475229896-6047-1-git-send-email-daniel.vetter@ffwll.ch
-rw-r--r-- | drivers/gpu/drm/drm_irq.c | 32 | ||||
-rw-r--r-- | include/drm/drm_crtc.h | 56 |
2 files changed, 73 insertions, 15 deletions
diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index 404a1ce7730c..b969a64a1514 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c | |||
@@ -1008,6 +1008,31 @@ static void send_vblank_event(struct drm_device *dev, | |||
1008 | * period. This helper function implements exactly the required vblank arming | 1008 | * period. This helper function implements exactly the required vblank arming |
1009 | * behaviour. | 1009 | * behaviour. |
1010 | * | 1010 | * |
1011 | * NOTE: Drivers using this to send out the event in struct &drm_crtc_state | ||
1012 | * as part of an atomic commit must ensure that the next vblank happens at | ||
1013 | * exactly the same time as the atomic commit is committed to the hardware. This | ||
1014 | * function itself does **not** protect again the next vblank interrupt racing | ||
1015 | * with either this function call or the atomic commit operation. A possible | ||
1016 | * sequence could be: | ||
1017 | * | ||
1018 | * 1. Driver commits new hardware state into vblank-synchronized registers. | ||
1019 | * 2. A vblank happens, committing the hardware state. Also the corresponding | ||
1020 | * vblank interrupt is fired off and fully processed by the interrupt | ||
1021 | * handler. | ||
1022 | * 3. The atomic commit operation proceeds to call drm_crtc_arm_vblank_event(). | ||
1023 | * 4. The event is only send out for the next vblank, which is wrong. | ||
1024 | * | ||
1025 | * An equivalent race can happen when the driver calls | ||
1026 | * drm_crtc_arm_vblank_event() before writing out the new hardware state. | ||
1027 | * | ||
1028 | * The only way to make this work safely is to prevent the vblank from firing | ||
1029 | * (and the hardware from committing anything else) until the entire atomic | ||
1030 | * commit sequence has run to completion. If the hardware does not have such a | ||
1031 | * feature (e.g. using a "go" bit), then it is unsafe to use this functions. | ||
1032 | * Instead drivers need to manually send out the event from their interrupt | ||
1033 | * handler by calling drm_crtc_send_vblank_event() and make sure that there's no | ||
1034 | * possible race with the hardware committing the atomic update. | ||
1035 | * | ||
1011 | * Caller must hold event lock. Caller must also hold a vblank reference for | 1036 | * Caller must hold event lock. Caller must also hold a vblank reference for |
1012 | * the event @e, which will be dropped when the next vblank arrives. | 1037 | * the event @e, which will be dropped when the next vblank arrives. |
1013 | */ | 1038 | */ |
@@ -1030,8 +1055,11 @@ EXPORT_SYMBOL(drm_crtc_arm_vblank_event); | |||
1030 | * @crtc: the source CRTC of the vblank event | 1055 | * @crtc: the source CRTC of the vblank event |
1031 | * @e: the event to send | 1056 | * @e: the event to send |
1032 | * | 1057 | * |
1033 | * Updates sequence # and timestamp on event, and sends it to userspace. | 1058 | * Updates sequence # and timestamp on event for the most recently processed |
1034 | * Caller must hold event lock. | 1059 | * vblank, and sends it to userspace. Caller must hold event lock. |
1060 | * | ||
1061 | * See drm_crtc_arm_vblank_event() for a helper which can be used in certain | ||
1062 | * situation, especially to send out events for atomic commit operations. | ||
1035 | */ | 1063 | */ |
1036 | void drm_crtc_send_vblank_event(struct drm_crtc *crtc, | 1064 | void drm_crtc_send_vblank_event(struct drm_crtc *crtc, |
1037 | struct drm_pending_vblank_event *e) | 1065 | struct drm_pending_vblank_event *e) |
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index a544b7502493..61932f55f788 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h | |||
@@ -109,8 +109,6 @@ struct drm_plane_helper_funcs; | |||
109 | * @ctm: Transformation matrix | 109 | * @ctm: Transformation matrix |
110 | * @gamma_lut: Lookup table for converting pixel data after the | 110 | * @gamma_lut: Lookup table for converting pixel data after the |
111 | * conversion matrix | 111 | * conversion matrix |
112 | * @event: optional pointer to a DRM event to signal upon completion of the | ||
113 | * state update | ||
114 | * @state: backpointer to global drm_atomic_state | 112 | * @state: backpointer to global drm_atomic_state |
115 | * | 113 | * |
116 | * Note that the distinction between @enable and @active is rather subtile: | 114 | * Note that the distinction between @enable and @active is rather subtile: |
@@ -159,6 +157,46 @@ struct drm_crtc_state { | |||
159 | struct drm_property_blob *ctm; | 157 | struct drm_property_blob *ctm; |
160 | struct drm_property_blob *gamma_lut; | 158 | struct drm_property_blob *gamma_lut; |
161 | 159 | ||
160 | /** | ||
161 | * @event: | ||
162 | * | ||
163 | * Optional pointer to a DRM event to signal upon completion of the | ||
164 | * state update. The driver must send out the event when the atomic | ||
165 | * commit operation completes. There are two cases: | ||
166 | * | ||
167 | * - The event is for a CRTC which is being disabled through this | ||
168 | * atomic commit. In that case the event can be send out any time | ||
169 | * after the hardware has stopped scanning out the current | ||
170 | * framebuffers. It should contain the timestamp and counter for the | ||
171 | * last vblank before the display pipeline was shut off. | ||
172 | * | ||
173 | * - For a CRTC which is enabled at the end of the commit (even when it | ||
174 | * undergoes an full modeset) the vblank timestamp and counter must | ||
175 | * be for the vblank right before the first frame that scans out the | ||
176 | * new set of buffers. Again the event can only be sent out after the | ||
177 | * hardware has stopped scanning out the old buffers. | ||
178 | * | ||
179 | * - Events for disabled CRTCs are not allowed, and drivers can ignore | ||
180 | * that case. | ||
181 | * | ||
182 | * This can be handled by the drm_crtc_send_vblank_event() function, | ||
183 | * which the driver should call on the provided event upon completion of | ||
184 | * the atomic commit. Note that if the driver supports vblank signalling | ||
185 | * and timestamping the vblank counters and timestamps must agree with | ||
186 | * the ones returned from page flip events. With the current vblank | ||
187 | * helper infrastructure this can be achieved by holding a vblank | ||
188 | * reference while the page flip is pending, acquired through | ||
189 | * drm_crtc_vblank_get() and released with drm_crtc_vblank_put(). | ||
190 | * Drivers are free to implement their own vblank counter and timestamp | ||
191 | * tracking though, e.g. if they have accurate timestamp registers in | ||
192 | * hardware. | ||
193 | * | ||
194 | * For hardware which supports some means to synchronize vblank | ||
195 | * interrupt delivery with committing display state there's also | ||
196 | * drm_crtc_arm_vblank_event(). See the documentation of that function | ||
197 | * for a detailed discussion of the constraints it needs to be used | ||
198 | * safely. | ||
199 | */ | ||
162 | struct drm_pending_vblank_event *event; | 200 | struct drm_pending_vblank_event *event; |
163 | 201 | ||
164 | struct drm_atomic_state *state; | 202 | struct drm_atomic_state *state; |
@@ -835,17 +873,9 @@ struct drm_mode_config_funcs { | |||
835 | * CRTC index supplied in &drm_event to userspace. | 873 | * CRTC index supplied in &drm_event to userspace. |
836 | * | 874 | * |
837 | * The drm core will supply a struct &drm_event in the event | 875 | * The drm core will supply a struct &drm_event in the event |
838 | * member of each CRTC's &drm_crtc_state structure. This can be handled by the | 876 | * member of each CRTC's &drm_crtc_state structure. See the |
839 | * drm_crtc_send_vblank_event() function, which the driver should call on | 877 | * documentation for &drm_crtc_state for more details about the precise |
840 | * the provided event upon completion of the atomic commit. Note that if | 878 | * semantics of this event. |
841 | * the driver supports vblank signalling and timestamping the vblank | ||
842 | * counters and timestamps must agree with the ones returned from page | ||
843 | * flip events. With the current vblank helper infrastructure this can | ||
844 | * be achieved by holding a vblank reference while the page flip is | ||
845 | * pending, acquired through drm_crtc_vblank_get() and released with | ||
846 | * drm_crtc_vblank_put(). Drivers are free to implement their own vblank | ||
847 | * counter and timestamp tracking though, e.g. if they have accurate | ||
848 | * timestamp registers in hardware. | ||
849 | * | 879 | * |
850 | * NOTE: | 880 | * NOTE: |
851 | * | 881 | * |