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

drm/i915/gt: Flush submission tasklet before waiting/retiring

A common bane of ours is arbitrary delays in ksoftirqd processing our
submission tasklet. Give the submission tasklet a kick before we wait to
avoid those delays eating into a tight timeout.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: Stuart Summers <stuart.summers@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20191008105655.13256-1-chris@chris-wilson.co.uk

+34 -14
+2 -1
drivers/gpu/drm/i915/gt/intel_engine.h
··· 407 407 engine->serial++; /* contexts lost */ 408 408 } 409 409 410 - bool intel_engine_is_idle(struct intel_engine_cs *engine); 411 410 bool intel_engines_are_idle(struct intel_gt *gt); 411 + bool intel_engine_is_idle(struct intel_engine_cs *engine); 412 + void intel_engine_flush_submission(struct intel_engine_cs *engine); 412 413 413 414 void intel_engines_reset_default_submission(struct intel_gt *gt); 414 415
+20 -13
drivers/gpu/drm/i915/gt/intel_engine_cs.c
··· 1040 1040 return idle; 1041 1041 } 1042 1042 1043 + void intel_engine_flush_submission(struct intel_engine_cs *engine) 1044 + { 1045 + struct tasklet_struct *t = &engine->execlists.tasklet; 1046 + 1047 + if (__tasklet_is_scheduled(t)) { 1048 + local_bh_disable(); 1049 + if (tasklet_trylock(t)) { 1050 + /* Must wait for any GPU reset in progress. */ 1051 + if (__tasklet_is_enabled(t)) 1052 + t->func(t->data); 1053 + tasklet_unlock(t); 1054 + } 1055 + local_bh_enable(); 1056 + } 1057 + 1058 + /* Otherwise flush the tasklet if it was running on another cpu */ 1059 + tasklet_unlock_wait(t); 1060 + } 1061 + 1043 1062 /** 1044 1063 * intel_engine_is_idle() - Report if the engine has finished process all work 1045 1064 * @engine: the intel_engine_cs ··· 1077 1058 1078 1059 /* Waiting to drain ELSP? */ 1079 1060 if (execlists_active(&engine->execlists)) { 1080 - struct tasklet_struct *t = &engine->execlists.tasklet; 1081 - 1082 1061 synchronize_hardirq(engine->i915->drm.pdev->irq); 1083 1062 1084 - local_bh_disable(); 1085 - if (tasklet_trylock(t)) { 1086 - /* Must wait for any GPU reset in progress. */ 1087 - if (__tasklet_is_enabled(t)) 1088 - t->func(t->data); 1089 - tasklet_unlock(t); 1090 - } 1091 - local_bh_enable(); 1092 - 1093 - /* Otherwise flush the tasklet if it was on another cpu */ 1094 - tasklet_unlock_wait(t); 1063 + intel_engine_flush_submission(engine); 1095 1064 1096 1065 if (execlists_active(&engine->execlists)) 1097 1066 return false;
+12
drivers/gpu/drm/i915/gt/intel_gt_requests.c
··· 4 4 * Copyright © 2019 Intel Corporation 5 5 */ 6 6 7 + #include "i915_drv.h" /* for_each_engine() */ 7 8 #include "i915_request.h" 8 9 #include "intel_gt.h" 9 10 #include "intel_gt_pm.h" ··· 20 19 break; 21 20 } 22 21 22 + static void flush_submission(struct intel_gt *gt) 23 + { 24 + struct intel_engine_cs *engine; 25 + enum intel_engine_id id; 26 + 27 + for_each_engine(engine, gt->i915, id) 28 + intel_engine_flush_submission(engine); 29 + } 30 + 23 31 long intel_gt_retire_requests_timeout(struct intel_gt *gt, long timeout) 24 32 { 25 33 struct intel_gt_timelines *timelines = &gt->timelines; ··· 41 31 interruptible = true; 42 32 if (unlikely(timeout < 0)) 43 33 timeout = -timeout, interruptible = false; 34 + 35 + flush_submission(gt); /* kick the ksoftirqd tasklets */ 44 36 45 37 spin_lock_irqsave(&timelines->lock, flags); 46 38 list_for_each_entry_safe(tl, tn, &timelines->active_list, link) {