Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

drm/atomic-helper: nonblocking commit support

Design ideas:

- split up the actual commit into different phases, and have
completions for each of them. This will be useful for the future
when we want to interleave phases much more aggressively, for e.g.
queue depth > 1. For not it's just a minimal optimization compared
to current common nonblocking implementation patterns from drivers,
which all stall for the entire commit to complete, including vblank
waits and cleanups.

- Extract a separate atomic_commit_hw hook since that's the part most
drivers will need to overwrite, hopefully allowing even more shared
code.

- Enforce EBUSY seamntics by attaching one of the completions to the
flip_done vblank event. Side benefit of forcing atomic drivers using
these helpers to implement event handlign at least semi-correct. I'm
evil that way ;-)

- Ridiculously modular, as usual.

- The main tracking unit for a commit stays struct drm_atomic_state,
and the ownership rules for that are unchanged. Ownership still
gets transferred to the driver (and subsequently to the worker) on
successful commits. What is added is a small, per-crtc, refcounted
structure to track pending commits called struct drm_crtc_commit.
No actual state is attached to that though, it's purely for ordering
and waiting.

- Dependencies are implicitly handled by assuming that any CRTC part
of &drm_atomic_state is a dependency, and that the current commit
must wait for any commits to complete on those CRTC. This way
drivers can easily add more depencies using
drm_atomic_get_crtc_state(), which is very natural since in most
case a dependency exists iff there's some bit of state that needs to
be cross checked.

Removing depencies is not possible, drivers simply need to be
careful to not include every CRTC in a commit if that's not
necessary. Which is a good idea anyway, since that also avoids
ww_mutex lock contention.

- Queue depth > 1 sees some prep work in this patch by adding a stall
paramater to drm_atomic_helper_swap_states(). To be able to push
commits entirely free-standing and in a deeper queue through the
back-end the driver must not access any obj->state pointers. This
means we need to track the old state in drm_atomic_state (much
easier with the consolidated arrays), and pass them all explicitly
to driver backends (this will be serious amounts of churn).

Once that's done stall can be set to false in swap_states.

v2: Dont ask for flip_done signalling when the CRTC is off and stays
off: Drivers don't handle events in that case. Instead complete right
away. This way future commits don't need to have special-case logic,
but can keep blocking for the flip_done completion.

v3: Tons of fixes:
- Stall for preceeding commit for real, not the current one by
accident.
- Add WARN_ON in case drivers don't fire the drm event.
- Don't double-free drm events.

v4: Make legacy cursor not stall.

v5: Extend the helper hook to cover the entire commit tail. Some
drivers need special code for cleanup and vblank waiting, this makes
it a bit more useful. Inspired by the rockchip driver.

v6: Add WARN_ON to catch drivers who forget to send out the
drm event.

v7: Fixup the stalls in swap_state for real!!

v8:
- Fixup trailing whitespace, spotted by Maarten.
- Actually wait for flip_done in cleanup_done, like the comment says
we should do. Thanks a lot for Tomeu for helping with debugging this
on.

v9: Now with awesome kerneldoc!

v10: Split out drm_crtc_commit tracking infrastructure.

v:
- Add missing static (Gustavo).
- Split out the sync functions, only do the actual nonblocking
logic in this patch (Maarten).

Cc: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
Tested-by: Tomeu Vizoso <tomeu.vizoso@collabora.com>
Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Cc: Tomeu Vizoso <tomeu.vizoso@gmail.com>
Cc: Daniel Stone <daniels@collabora.com>
Tested-by: Liviu Dudau <Liviu.Dudau@arm.com>
Reviewed-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Testcase: igt/kms_flip/*
Testcase: igt/kms_cursor*
Testcase: igt/kms*plane*
Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1465388359-8070-10-git-send-email-daniel.vetter@ffwll.ch

+141 -46
+98 -46
drivers/gpu/drm/drm_atomic_helper.c
··· 1120 1120 EXPORT_SYMBOL(drm_atomic_helper_wait_for_vblanks); 1121 1121 1122 1122 /** 1123 - * drm_atomic_helper_commit - commit validated state object 1124 - * @dev: DRM device 1125 - * @state: the driver state object 1126 - * @nonblocking: whether nonblocking behavior is requested. 1123 + * drm_atomic_helper_commit_tail - commit atomic update to hardware 1124 + * @state: new modeset state to be committed 1127 1125 * 1128 - * This function commits a with drm_atomic_helper_check() pre-validated state 1129 - * object. This can still fail when e.g. the framebuffer reservation fails. For 1130 - * now this doesn't implement nonblocking commits. 1126 + * This is the default implemenation for the ->atomic_commit_tail() hook of the 1127 + * &drm_mode_config_helper_funcs vtable. 1131 1128 * 1132 - * Note that right now this function does not support nonblocking commits, hence 1133 - * driver writers must implement their own version for now. Also note that the 1134 - * default ordering of how the various stages are called is to match the legacy 1135 - * modeset helper library closest. One peculiarity of that is that it doesn't 1136 - * mesh well with runtime PM at all. 1129 + * Note that the default ordering of how the various stages are called is to 1130 + * match the legacy modeset helper library closest. One peculiarity of that is 1131 + * that it doesn't mesh well with runtime PM at all. 1137 1132 * 1138 - * For drivers supporting runtime PM the recommended sequence is 1133 + * For drivers supporting runtime PM the recommended sequence is instead :: 1139 1134 * 1140 1135 * drm_atomic_helper_commit_modeset_disables(dev, state); 1141 1136 * ··· 1138 1143 * 1139 1144 * drm_atomic_helper_commit_planes(dev, state, true); 1140 1145 * 1141 - * See the kerneldoc entries for these three functions for more details. 1146 + * for committing the atomic update to hardware. See the kerneldoc entries for 1147 + * these three functions for more details. 1148 + */ 1149 + void drm_atomic_helper_commit_tail(struct drm_atomic_state *state) 1150 + { 1151 + struct drm_device *dev = state->dev; 1152 + 1153 + drm_atomic_helper_commit_modeset_disables(dev, state); 1154 + 1155 + drm_atomic_helper_commit_planes(dev, state, false); 1156 + 1157 + drm_atomic_helper_commit_modeset_enables(dev, state); 1158 + 1159 + drm_atomic_helper_commit_hw_done(state); 1160 + 1161 + drm_atomic_helper_wait_for_vblanks(dev, state); 1162 + 1163 + drm_atomic_helper_cleanup_planes(dev, state); 1164 + } 1165 + EXPORT_SYMBOL(drm_atomic_helper_commit_tail); 1166 + 1167 + static void commit_tail(struct drm_atomic_state *state) 1168 + { 1169 + struct drm_device *dev = state->dev; 1170 + struct drm_mode_config_helper_funcs *funcs; 1171 + 1172 + funcs = dev->mode_config.helper_private; 1173 + 1174 + drm_atomic_helper_wait_for_fences(dev, state); 1175 + 1176 + drm_atomic_helper_wait_for_dependencies(state); 1177 + 1178 + if (funcs && funcs->atomic_commit_tail) 1179 + funcs->atomic_commit_tail(state); 1180 + else 1181 + drm_atomic_helper_commit_tail(state); 1182 + 1183 + drm_atomic_helper_commit_cleanup_done(state); 1184 + 1185 + drm_atomic_state_free(state); 1186 + } 1187 + 1188 + static void commit_work(struct work_struct *work) 1189 + { 1190 + struct drm_atomic_state *state = container_of(work, 1191 + struct drm_atomic_state, 1192 + commit_work); 1193 + commit_tail(state); 1194 + } 1195 + 1196 + /** 1197 + * drm_atomic_helper_commit - commit validated state object 1198 + * @dev: DRM device 1199 + * @state: the driver state object 1200 + * @nonblock: whether nonblocking behavior is requested. 1201 + * 1202 + * This function commits a with drm_atomic_helper_check() pre-validated state 1203 + * object. This can still fail when e.g. the framebuffer reservation fails. This 1204 + * function implements nonblocking commits, using 1205 + * drm_atomic_helper_setup_commit() and related functions. 1206 + * 1207 + * Note that right now this function does not support nonblocking commits, hence 1208 + * driver writers must implement their own version for now. 1209 + * 1210 + * Committing the actual hardware state is done through the 1211 + * ->atomic_commit_tail() callback of the &drm_mode_config_helper_funcs vtable, 1212 + * or it's default implementation drm_atomic_helper_commit_tail(). 1142 1213 * 1143 1214 * RETURNS: 1144 1215 * Zero for success or -errno. ··· 1215 1154 { 1216 1155 int ret; 1217 1156 1218 - if (nonblock) 1219 - return -EBUSY; 1220 - 1221 1157 ret = drm_atomic_helper_setup_commit(state, nonblock); 1222 1158 if (ret) 1223 1159 return ret; 1160 + 1161 + INIT_WORK(&state->commit_work, commit_work); 1224 1162 1225 1163 ret = drm_atomic_helper_prepare_planes(dev, state); 1226 1164 if (ret) ··· 1247 1187 * update. Which is important since compositors need to figure out the 1248 1188 * composition of the next frame right after having submitted the 1249 1189 * current layout. 1190 + * 1191 + * NOTE: Commit work has multiple phases, first hardware commit, then 1192 + * cleanup. We want them to overlap, hence need system_unbound_wq to 1193 + * make sure work items don't artifically stall on each another. 1250 1194 */ 1251 1195 1252 - drm_atomic_helper_wait_for_fences(dev, state); 1253 - 1254 - drm_atomic_helper_wait_for_dependencies(state); 1255 - 1256 - drm_atomic_helper_commit_modeset_disables(dev, state); 1257 - 1258 - drm_atomic_helper_commit_planes(dev, state, false); 1259 - 1260 - drm_atomic_helper_commit_modeset_enables(dev, state); 1261 - 1262 - drm_atomic_helper_commit_hw_done(state); 1263 - 1264 - drm_atomic_helper_wait_for_vblanks(dev, state); 1265 - 1266 - drm_atomic_helper_cleanup_planes(dev, state); 1267 - 1268 - drm_atomic_helper_commit_cleanup_done(state); 1269 - 1270 - drm_atomic_state_free(state); 1196 + if (nonblock) 1197 + queue_work(system_unbound_wq, &state->commit_work); 1198 + else 1199 + commit_tail(state); 1271 1200 1272 1201 return 0; 1273 1202 } ··· 1265 1216 /** 1266 1217 * DOC: implementing nonblocking commit 1267 1218 * 1268 - * For now the atomic helpers don't support nonblocking commit directly. If 1269 - * there is real need it could be added though, using the dma-buf fence 1270 - * infrastructure for generic synchronization with outstanding rendering. 1271 - * 1272 - * For now drivers have to implement nonblocking commit themselves, with the 1273 - * following sequence being the recommended one: 1219 + * Nonblocking atomic commits have to be implemented in the following sequence: 1274 1220 * 1275 1221 * 1. Run drm_atomic_helper_prepare_planes() first. This is the only function 1276 1222 * which commit needs to call which can fail, so we want to run it first and ··· 1277 1233 * cancelled updates. Note that it is important to ensure that the framebuffer 1278 1234 * cleanup is still done when cancelling. 1279 1235 * 1280 - * For sufficient parallelism it is recommended to have a work item per crtc 1281 - * (for updates which don't touch global state) and a global one. Then we only 1282 - * need to synchronize with the crtc work items for changed crtcs and the global 1283 - * work item, which allows nice concurrent updates on disjoint sets of crtcs. 1236 + * Asynchronous workers need to have sufficient parallelism to be able to run 1237 + * different atomic commits on different CRTCs in parallel. The simplest way to 1238 + * achive this is by running them on the &system_unbound_wq work queue. Note 1239 + * that drivers are not required to split up atomic commits and run an 1240 + * individual commit in parallel - userspace is supposed to do that if it cares. 1241 + * But it might be beneficial to do that for modesets, since those necessarily 1242 + * must be done as one global operation, and enabling or disabling a CRTC can 1243 + * take a long time. But even that is not required. 1284 1244 * 1285 1245 * 3. The software state is updated synchronously with 1286 1246 * drm_atomic_helper_swap_state(). Doing this under the protection of all modeset ··· 1297 1249 * commit helpers: a) pre-plane commit b) plane commit c) post-plane commit and 1298 1250 * then cleaning up the framebuffers after the old framebuffer is no longer 1299 1251 * being displayed. 1252 + * 1253 + * The above scheme is implemented in the atomic helper libraries in 1254 + * drm_atomic_helper_commit() using a bunch of helper functions. See 1255 + * drm_atomic_helper_setup_commit() for a starting point. 1300 1256 */ 1301 1257 1302 1258 static int stall_checks(struct drm_crtc *crtc, bool nonblock)
+1
include/drm/drm_atomic_helper.h
··· 38 38 struct drm_atomic_state *state); 39 39 int drm_atomic_helper_check(struct drm_device *dev, 40 40 struct drm_atomic_state *state); 41 + void drm_atomic_helper_commit_tail(struct drm_atomic_state *state); 41 42 int drm_atomic_helper_commit(struct drm_device *dev, 42 43 struct drm_atomic_state *state, 43 44 bool nonblock);
+3
include/drm/drm_crtc.h
··· 2248 2248 * @async_page_flip: does this device support async flips on the primary plane? 2249 2249 * @cursor_width: hint to userspace for max cursor width 2250 2250 * @cursor_height: hint to userspace for max cursor height 2251 + * @helper_private: mid-layer private data 2251 2252 * 2252 2253 * Core mode resource tracking structure. All CRTC, encoders, and connectors 2253 2254 * enumerated by the driver are added here, as are global properties. Some ··· 2392 2391 2393 2392 /* cursor size */ 2394 2393 uint32_t cursor_width, cursor_height; 2394 + 2395 + struct drm_mode_config_helper_funcs *helper_private; 2395 2396 }; 2396 2397 2397 2398 /**
+39
include/drm/drm_modeset_helper_vtables.h
··· 931 931 plane->helper_private = funcs; 932 932 } 933 933 934 + /** 935 + * struct drm_mode_config_helper_funcs - global modeset helper operations 936 + * 937 + * These helper functions are used by the atomic helpers. 938 + */ 939 + struct drm_mode_config_helper_funcs { 940 + /** 941 + * @atomic_commit_tail: 942 + * 943 + * This hook is used by the default atomic_commit() hook implemented in 944 + * drm_atomic_helper_commit() together with the nonblocking commit 945 + * helpers (see drm_atomic_helper_setup_commit() for a starting point) 946 + * to implement blocking and nonblocking commits easily. It is not used 947 + * by the atomic helpers 948 + * 949 + * This hook should first commit the given atomic state to the hardware. 950 + * But drivers can add more waiting calls at the start of their 951 + * implementation, e.g. to wait for driver-internal request for implicit 952 + * syncing, before starting to commit the update to the hardware. 953 + * 954 + * After the atomic update is committed to the hardware this hook needs 955 + * to call drm_atomic_helper_commit_hw_done(). Then wait for the upate 956 + * to be executed by the hardware, for example using 957 + * drm_atomic_helper_wait_for_vblanks(), and then clean up the old 958 + * framebuffers using drm_atomic_helper_cleanup_planes(). 959 + * 960 + * When disabling a CRTC this hook _must_ stall for the commit to 961 + * complete. Vblank waits don't work on disabled CRTC, hence the core 962 + * can't take care of this. And it also can't rely on the vblank event, 963 + * since that can be signalled already when the screen shows black, 964 + * which can happen much earlier than the last hardware access needed to 965 + * shut off the display pipeline completely. 966 + * 967 + * This hook is optional, the default implementation is 968 + * drm_atomic_helper_commit_tail(). 969 + */ 970 + void (*atomic_commit_tail)(struct drm_atomic_state *state); 971 + }; 972 + 934 973 #endif