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

drm/i915/guc: Update intel_gt_wait_for_idle to work with GuC

When running the GuC the GPU can't be considered idle if the GuC still
has contexts pinned. As such, a call has been added in
intel_gt_wait_for_idle to idle the UC and in turn the GuC by waiting for
the number of unpinned contexts to go to zero.

v2: rtimeout -> remaining_timeout
v3: Drop unnecessary includes, guc_submission_busy_loop ->
guc_submission_send_busy_loop, drop negatie timeout trick, move a
refactor of guc_context_unpin to earlier path (John H)
v4: Add stddef.h back into intel_gt_requests.h, sort circuit idle
function if not in GuC submission mode

Cc: John Harrison <john.c.harrison@intel.com>
Signed-off-by: Matthew Brost <matthew.brost@intel.com>
Reviewed-by: John Harrison <John.C.Harrison@Intel.com>
Signed-off-by: John Harrison <John.C.Harrison@Intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20210721215101.139794-16-matthew.brost@intel.com

authored by

Matthew Brost and committed by
John Harrison
b97060a9 f4eb1f3f

+134 -28
+2 -1
drivers/gpu/drm/i915/gem/i915_gem_mman.c
··· 645 645 goto insert; 646 646 647 647 /* Attempt to reap some mmap space from dead objects */ 648 - err = intel_gt_retire_requests_timeout(&i915->gt, MAX_SCHEDULE_TIMEOUT); 648 + err = intel_gt_retire_requests_timeout(&i915->gt, MAX_SCHEDULE_TIMEOUT, 649 + NULL); 649 650 if (err) 650 651 goto err; 651 652
+19
drivers/gpu/drm/i915/gt/intel_gt.c
··· 585 585 GEM_BUG_ON(intel_gt_pm_is_awake(gt)); 586 586 } 587 587 588 + int intel_gt_wait_for_idle(struct intel_gt *gt, long timeout) 589 + { 590 + long remaining_timeout; 591 + 592 + /* If the device is asleep, we have no requests outstanding */ 593 + if (!intel_gt_pm_is_awake(gt)) 594 + return 0; 595 + 596 + while ((timeout = intel_gt_retire_requests_timeout(gt, timeout, 597 + &remaining_timeout)) > 0) { 598 + cond_resched(); 599 + if (signal_pending(current)) 600 + return -EINTR; 601 + } 602 + 603 + return timeout ? timeout : intel_uc_wait_for_idle(&gt->uc, 604 + remaining_timeout); 605 + } 606 + 588 607 int intel_gt_init(struct intel_gt *gt) 589 608 { 590 609 int err;
+2
drivers/gpu/drm/i915/gt/intel_gt.h
··· 48 48 49 49 void intel_gt_driver_late_release(struct intel_gt *gt); 50 50 51 + int intel_gt_wait_for_idle(struct intel_gt *gt, long timeout); 52 + 51 53 void intel_gt_check_and_clear_faults(struct intel_gt *gt); 52 54 void intel_gt_clear_error_registers(struct intel_gt *gt, 53 55 intel_engine_mask_t engine_mask);
+5 -16
drivers/gpu/drm/i915/gt/intel_gt_requests.c
··· 130 130 GEM_BUG_ON(engine->retire); 131 131 } 132 132 133 - long intel_gt_retire_requests_timeout(struct intel_gt *gt, long timeout) 133 + long intel_gt_retire_requests_timeout(struct intel_gt *gt, long timeout, 134 + long *remaining_timeout) 134 135 { 135 136 struct intel_gt_timelines *timelines = &gt->timelines; 136 137 struct intel_timeline *tl, *tn; ··· 196 195 if (flush_submission(gt, timeout)) /* Wait, there's more! */ 197 196 active_count++; 198 197 198 + if (remaining_timeout) 199 + *remaining_timeout = timeout; 200 + 199 201 return active_count ? timeout : 0; 200 - } 201 - 202 - int intel_gt_wait_for_idle(struct intel_gt *gt, long timeout) 203 - { 204 - /* If the device is asleep, we have no requests outstanding */ 205 - if (!intel_gt_pm_is_awake(gt)) 206 - return 0; 207 - 208 - while ((timeout = intel_gt_retire_requests_timeout(gt, timeout)) > 0) { 209 - cond_resched(); 210 - if (signal_pending(current)) 211 - return -EINTR; 212 - } 213 - 214 - return timeout; 215 202 } 216 203 217 204 static void retire_work_handler(struct work_struct *work)
+5 -4
drivers/gpu/drm/i915/gt/intel_gt_requests.h
··· 6 6 #ifndef INTEL_GT_REQUESTS_H 7 7 #define INTEL_GT_REQUESTS_H 8 8 9 + #include <stddef.h> 10 + 9 11 struct intel_engine_cs; 10 12 struct intel_gt; 11 13 struct intel_timeline; 12 14 13 - long intel_gt_retire_requests_timeout(struct intel_gt *gt, long timeout); 15 + long intel_gt_retire_requests_timeout(struct intel_gt *gt, long timeout, 16 + long *remaining_timeout); 14 17 static inline void intel_gt_retire_requests(struct intel_gt *gt) 15 18 { 16 - intel_gt_retire_requests_timeout(gt, 0); 19 + intel_gt_retire_requests_timeout(gt, 0, NULL); 17 20 } 18 21 19 22 void intel_engine_init_retire(struct intel_engine_cs *engine); 20 23 void intel_engine_add_retire(struct intel_engine_cs *engine, 21 24 struct intel_timeline *tl); 22 25 void intel_engine_fini_retire(struct intel_engine_cs *engine); 23 - 24 - int intel_gt_wait_for_idle(struct intel_gt *gt, long timeout); 25 26 26 27 void intel_gt_init_requests(struct intel_gt *gt); 27 28 void intel_gt_park_requests(struct intel_gt *gt);
+4
drivers/gpu/drm/i915/gt/uc/intel_guc.h
··· 39 39 spinlock_t irq_lock; 40 40 unsigned int msg_enabled_mask; 41 41 42 + atomic_t outstanding_submission_g2h; 43 + 42 44 struct { 43 45 void (*reset)(struct intel_guc *guc); 44 46 void (*enable)(struct intel_guc *guc); ··· 246 244 guc->msg_enabled_mask &= ~mask; 247 245 spin_unlock_irq(&guc->irq_lock); 248 246 } 247 + 248 + int intel_guc_wait_for_idle(struct intel_guc *guc, long timeout); 249 249 250 250 int intel_guc_reset_engine(struct intel_guc *guc, 251 251 struct intel_engine_cs *engine);
+1
drivers/gpu/drm/i915/gt/uc/intel_guc_ct.c
··· 109 109 INIT_LIST_HEAD(&ct->requests.incoming); 110 110 INIT_WORK(&ct->requests.worker, ct_incoming_request_worker_func); 111 111 tasklet_setup(&ct->receive_tasklet, ct_receive_tasklet_func); 112 + init_waitqueue_head(&ct->wq); 112 113 } 113 114 114 115 static inline const char *guc_ct_buffer_type_to_str(u32 type)
+4
drivers/gpu/drm/i915/gt/uc/intel_guc_ct.h
··· 10 10 #include <linux/spinlock.h> 11 11 #include <linux/workqueue.h> 12 12 #include <linux/ktime.h> 13 + #include <linux/wait.h> 13 14 14 15 #include "intel_guc_fwif.h" 15 16 ··· 68 67 } ctbs; 69 68 70 69 struct tasklet_struct receive_tasklet; 70 + 71 + /** @wq: wait queue for g2h chanenl */ 72 + wait_queue_head_t wq; 71 73 72 74 struct { 73 75 u16 last_fence; /* last fence used to send request */
+83 -5
drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c
··· 252 252 xa_store_irq(&guc->context_lookup, id, ce, GFP_ATOMIC); 253 253 } 254 254 255 + static int guc_submission_send_busy_loop(struct intel_guc *guc, 256 + const u32 *action, 257 + u32 len, 258 + u32 g2h_len_dw, 259 + bool loop) 260 + { 261 + int err; 262 + 263 + err = intel_guc_send_busy_loop(guc, action, len, g2h_len_dw, loop); 264 + 265 + if (!err && g2h_len_dw) 266 + atomic_inc(&guc->outstanding_submission_g2h); 267 + 268 + return err; 269 + } 270 + 271 + static int guc_wait_for_pending_msg(struct intel_guc *guc, 272 + atomic_t *wait_var, 273 + bool interruptible, 274 + long timeout) 275 + { 276 + const int state = interruptible ? 277 + TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE; 278 + DEFINE_WAIT(wait); 279 + 280 + might_sleep(); 281 + GEM_BUG_ON(timeout < 0); 282 + 283 + if (!atomic_read(wait_var)) 284 + return 0; 285 + 286 + if (!timeout) 287 + return -ETIME; 288 + 289 + for (;;) { 290 + prepare_to_wait(&guc->ct.wq, &wait, state); 291 + 292 + if (!atomic_read(wait_var)) 293 + break; 294 + 295 + if (signal_pending_state(state, current)) { 296 + timeout = -EINTR; 297 + break; 298 + } 299 + 300 + if (!timeout) { 301 + timeout = -ETIME; 302 + break; 303 + } 304 + 305 + timeout = io_schedule_timeout(timeout); 306 + } 307 + finish_wait(&guc->ct.wq, &wait); 308 + 309 + return (timeout < 0) ? timeout : 0; 310 + } 311 + 312 + int intel_guc_wait_for_idle(struct intel_guc *guc, long timeout) 313 + { 314 + if (!intel_uc_uses_guc_submission(&guc_to_gt(guc)->uc)) 315 + return 0; 316 + 317 + return guc_wait_for_pending_msg(guc, &guc->outstanding_submission_g2h, 318 + true, timeout); 319 + } 320 + 255 321 static int guc_add_request(struct intel_guc *guc, struct i915_request *rq) 256 322 { 257 323 int err; ··· 344 278 345 279 err = intel_guc_send_nb(guc, action, len, g2h_len_dw); 346 280 if (!enabled && !err) { 281 + atomic_inc(&guc->outstanding_submission_g2h); 347 282 set_context_enabled(ce); 348 283 } else if (!enabled) { 349 284 clr_context_pending_enable(ce); ··· 802 735 offset, 803 736 }; 804 737 805 - return intel_guc_send_busy_loop(guc, action, ARRAY_SIZE(action), 0, true); 738 + return guc_submission_send_busy_loop(guc, action, ARRAY_SIZE(action), 739 + 0, true); 806 740 } 807 741 808 742 static int register_context(struct intel_context *ce) ··· 823 755 guc_id, 824 756 }; 825 757 826 - return intel_guc_send_busy_loop(guc, action, ARRAY_SIZE(action), 827 - G2H_LEN_DW_DEREGISTER_CONTEXT, true); 758 + return guc_submission_send_busy_loop(guc, action, ARRAY_SIZE(action), 759 + G2H_LEN_DW_DEREGISTER_CONTEXT, 760 + true); 828 761 } 829 762 830 763 static int deregister_context(struct intel_context *ce, u32 guc_id) ··· 970 901 971 902 intel_context_get(ce); 972 903 973 - intel_guc_send_busy_loop(guc, action, ARRAY_SIZE(action), 974 - G2H_LEN_DW_SCHED_CONTEXT_MODE_SET, true); 904 + guc_submission_send_busy_loop(guc, action, ARRAY_SIZE(action), 905 + G2H_LEN_DW_SCHED_CONTEXT_MODE_SET, true); 975 906 } 976 907 977 908 static u16 prep_context_pending_disable(struct intel_context *ce) ··· 1513 1444 return ce; 1514 1445 } 1515 1446 1447 + static void decr_outstanding_submission_g2h(struct intel_guc *guc) 1448 + { 1449 + if (atomic_dec_and_test(&guc->outstanding_submission_g2h)) 1450 + wake_up_all(&guc->ct.wq); 1451 + } 1452 + 1516 1453 int intel_guc_deregister_done_process_msg(struct intel_guc *guc, 1517 1454 const u32 *msg, 1518 1455 u32 len) ··· 1553 1478 release_guc_id(guc, ce); 1554 1479 lrc_destroy(&ce->ref); 1555 1480 } 1481 + 1482 + decr_outstanding_submission_g2h(guc); 1556 1483 1557 1484 return 0; 1558 1485 } ··· 1604 1527 spin_unlock_irqrestore(&ce->guc_state.lock, flags); 1605 1528 } 1606 1529 1530 + decr_outstanding_submission_g2h(guc); 1607 1531 intel_context_put(ce); 1608 1532 1609 1533 return 0;
+5
drivers/gpu/drm/i915/gt/uc/intel_uc.h
··· 81 81 #undef uc_state_checkers 82 82 #undef __uc_state_checker 83 83 84 + static inline int intel_uc_wait_for_idle(struct intel_uc *uc, long timeout) 85 + { 86 + return intel_guc_wait_for_idle(&uc->guc, timeout); 87 + } 88 + 84 89 #define intel_uc_ops_function(_NAME, _OPS, _TYPE, _RET) \ 85 90 static inline _TYPE intel_uc_##_NAME(struct intel_uc *uc) \ 86 91 { \
+1
drivers/gpu/drm/i915/i915_gem_evict.c
··· 27 27 */ 28 28 29 29 #include "gem/i915_gem_context.h" 30 + #include "gt/intel_gt.h" 30 31 #include "gt/intel_gt_requests.h" 31 32 32 33 #include "i915_drv.h"
+1 -1
drivers/gpu/drm/i915/selftests/igt_live_test.c
··· 5 5 */ 6 6 7 7 #include "i915_drv.h" 8 - #include "gt/intel_gt_requests.h" 8 + #include "gt/intel_gt.h" 9 9 10 10 #include "../i915_selftest.h" 11 11 #include "igt_flush_test.h"
+2 -1
drivers/gpu/drm/i915/selftests/mock_gem_device.c
··· 52 52 do { 53 53 for_each_engine(engine, gt, id) 54 54 mock_engine_flush(engine); 55 - } while (intel_gt_retire_requests_timeout(gt, MAX_SCHEDULE_TIMEOUT)); 55 + } while (intel_gt_retire_requests_timeout(gt, MAX_SCHEDULE_TIMEOUT, 56 + NULL)); 56 57 } 57 58 58 59 static void mock_device_release(struct drm_device *dev)