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

drm/i915/gt: Prevent timeslicing into unpreemptable requests

We have a I915_REQUEST_NOPREEMPT flag that we set when we must prevent
the HW from preempting during the course of this request. We need to
honour this flag and protect the HW even if we have a heartbeat request,
or other maximum priority barrier, pending. As such, restrict the
timeslicing check to avoid preempting into the topmost priority band,
leaving the unpreemptable requests in blissful peace running
uninterrupted on the HW.

v2: Set the I915_PRIORITY_BARRIER to be less than
I915_PRIORITY_UNPREEMPTABLE so that we never submit a request
(heartbeat or barrier) that can legitimately preempt the current
non-premptable request.

Fixes: 2a98f4e65bba ("drm/i915: add infrastructure to hold off preemption on a request")
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20200527162418.24755-1-chris@chris-wilson.co.uk
(cherry picked from commit b72f02d78e4f257761ed003444ae52083f962076)
Signed-off-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>

authored by

Chris Wilson and committed by
Joonas Lahtinen
4178b5a6 3ffbe353

+119 -2
+1
drivers/gpu/drm/i915/gt/intel_lrc.c
··· 1925 1925 if (!list_is_last(&rq->sched.link, &engine->active.requests)) 1926 1926 hint = max(hint, rq_prio(list_next_entry(rq, sched.link))); 1927 1927 1928 + GEM_BUG_ON(hint >= I915_PRIORITY_UNPREEMPTABLE); 1928 1929 return hint >= effective_prio(rq); 1929 1930 } 1930 1931
+117 -1
drivers/gpu/drm/i915/gt/selftest_lrc.c
··· 823 823 } 824 824 } 825 825 826 - err = release_queue(outer, vma, n, INT_MAX); 826 + err = release_queue(outer, vma, n, I915_PRIORITY_BARRIER); 827 827 if (err) 828 828 goto out; 829 829 ··· 1286 1286 i915_gem_object_unpin_map(obj); 1287 1287 err_obj: 1288 1288 i915_gem_object_put(obj); 1289 + return err; 1290 + } 1291 + 1292 + static int live_timeslice_nopreempt(void *arg) 1293 + { 1294 + struct intel_gt *gt = arg; 1295 + struct intel_engine_cs *engine; 1296 + enum intel_engine_id id; 1297 + struct igt_spinner spin; 1298 + int err = 0; 1299 + 1300 + /* 1301 + * We should not timeslice into a request that is marked with 1302 + * I915_REQUEST_NOPREEMPT. 1303 + */ 1304 + if (!IS_ACTIVE(CONFIG_DRM_I915_TIMESLICE_DURATION)) 1305 + return 0; 1306 + 1307 + if (igt_spinner_init(&spin, gt)) 1308 + return -ENOMEM; 1309 + 1310 + for_each_engine(engine, gt, id) { 1311 + struct intel_context *ce; 1312 + struct i915_request *rq; 1313 + unsigned long timeslice; 1314 + 1315 + if (!intel_engine_has_preemption(engine)) 1316 + continue; 1317 + 1318 + ce = intel_context_create(engine); 1319 + if (IS_ERR(ce)) { 1320 + err = PTR_ERR(ce); 1321 + break; 1322 + } 1323 + 1324 + engine_heartbeat_disable(engine); 1325 + timeslice = xchg(&engine->props.timeslice_duration_ms, 1); 1326 + 1327 + /* Create an unpreemptible spinner */ 1328 + 1329 + rq = igt_spinner_create_request(&spin, ce, MI_ARB_CHECK); 1330 + intel_context_put(ce); 1331 + if (IS_ERR(rq)) { 1332 + err = PTR_ERR(rq); 1333 + goto out_heartbeat; 1334 + } 1335 + 1336 + i915_request_get(rq); 1337 + i915_request_add(rq); 1338 + 1339 + if (!igt_wait_for_spinner(&spin, rq)) { 1340 + i915_request_put(rq); 1341 + err = -ETIME; 1342 + goto out_spin; 1343 + } 1344 + 1345 + set_bit(I915_FENCE_FLAG_NOPREEMPT, &rq->fence.flags); 1346 + i915_request_put(rq); 1347 + 1348 + /* Followed by a maximum priority barrier (heartbeat) */ 1349 + 1350 + ce = intel_context_create(engine); 1351 + if (IS_ERR(ce)) { 1352 + err = PTR_ERR(rq); 1353 + goto out_spin; 1354 + } 1355 + 1356 + rq = intel_context_create_request(ce); 1357 + intel_context_put(ce); 1358 + if (IS_ERR(rq)) { 1359 + err = PTR_ERR(rq); 1360 + goto out_spin; 1361 + } 1362 + 1363 + rq->sched.attr.priority = I915_PRIORITY_BARRIER; 1364 + i915_request_get(rq); 1365 + i915_request_add(rq); 1366 + 1367 + /* 1368 + * Wait until the barrier is in ELSP, and we know timeslicing 1369 + * will have been activated. 1370 + */ 1371 + if (wait_for_submit(engine, rq, HZ / 2)) { 1372 + i915_request_put(rq); 1373 + err = -ETIME; 1374 + goto out_spin; 1375 + } 1376 + 1377 + /* 1378 + * Since the ELSP[0] request is unpreemptible, it should not 1379 + * allow the maximum priority barrier through. Wait long 1380 + * enough to see if it is timesliced in by mistake. 1381 + */ 1382 + if (i915_request_wait(rq, 0, timeslice_threshold(engine)) >= 0) { 1383 + pr_err("%s: I915_PRIORITY_BARRIER request completed, bypassing no-preempt request\n", 1384 + engine->name); 1385 + err = -EINVAL; 1386 + } 1387 + i915_request_put(rq); 1388 + 1389 + out_spin: 1390 + igt_spinner_end(&spin); 1391 + out_heartbeat: 1392 + xchg(&engine->props.timeslice_duration_ms, timeslice); 1393 + engine_heartbeat_enable(engine); 1394 + if (err) 1395 + break; 1396 + 1397 + if (igt_flush_test(gt->i915)) { 1398 + err = -EIO; 1399 + break; 1400 + } 1401 + } 1402 + 1403 + igt_spinner_fini(&spin); 1289 1404 return err; 1290 1405 } 1291 1406 ··· 4411 4296 SUBTEST(live_timeslice_preempt), 4412 4297 SUBTEST(live_timeslice_rewind), 4413 4298 SUBTEST(live_timeslice_queue), 4299 + SUBTEST(live_timeslice_nopreempt), 4414 4300 SUBTEST(live_busywait_preempt), 4415 4301 SUBTEST(live_preempt), 4416 4302 SUBTEST(live_late_preempt),
+1 -1
drivers/gpu/drm/i915/i915_priolist_types.h
··· 42 42 * active request. 43 43 */ 44 44 #define I915_PRIORITY_UNPREEMPTABLE INT_MAX 45 - #define I915_PRIORITY_BARRIER INT_MAX 45 + #define I915_PRIORITY_BARRIER (I915_PRIORITY_UNPREEMPTABLE - 1) 46 46 47 47 struct i915_priolist { 48 48 struct list_head requests[I915_PRIORITY_COUNT];