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/xe: Skip exec queue schedule toggle if queue is idle during suspend

If an exec queue is idle, there is no need to issue a schedule disable
to the GuC when suspending the queue’s execution. Opportunistically skip
this step if the queue is idle and not a parallel queue. Parallel queues
must have their scheduling state flipped in the GuC due to limitations
in how submission is implemented in run_job().

Also if all pagefault queues can skip the schedule disable during a
switch to dma-fence mode, do not schedule a resume for the pagefault
queues after the next submission.

v2:
- Don't touch the LRC tail is queue is suspended but enabled in run_job
(CI)

Signed-off-by: Matthew Brost <matthew.brost@intel.com>
Reviewed-by: Thomas Hellström <thomas.hellstrom@linux.intel.com>
Link: https://patch.msgid.link/20251212182847.1683222-5-matthew.brost@intel.com

+70 -4
+17
drivers/gpu/drm/xe/xe_exec_queue.h
··· 162 162 163 163 struct xe_lrc *xe_exec_queue_lrc(struct xe_exec_queue *q); 164 164 165 + /** 166 + * xe_exec_queue_idle_skip_suspend() - Can exec queue skip suspend 167 + * @q: The exec_queue 168 + * 169 + * If an exec queue is not parallel and is idle, the suspend steps can be 170 + * skipped in the submission backend immediatley signaling the suspend fence. 171 + * Parallel queues cannot skip this step due to limitations in the submission 172 + * backend. 173 + * 174 + * Return: True if exec queue is idle and can skip suspend steps, False 175 + * otherwise 176 + */ 177 + static inline bool xe_exec_queue_idle_skip_suspend(struct xe_exec_queue *q) 178 + { 179 + return !xe_exec_queue_is_parallel(q) && xe_exec_queue_is_idle(q); 180 + } 181 + 165 182 #endif
+52 -3
drivers/gpu/drm/xe/xe_guc_submit.c
··· 75 75 #define EXEC_QUEUE_STATE_EXTRA_REF (1 << 11) 76 76 #define EXEC_QUEUE_STATE_PENDING_RESUME (1 << 12) 77 77 #define EXEC_QUEUE_STATE_PENDING_TDR_EXIT (1 << 13) 78 + #define EXEC_QUEUE_STATE_IDLE_SKIP_SUSPEND (1 << 14) 78 79 79 80 static bool exec_queue_registered(struct xe_exec_queue *q) 80 81 { ··· 265 264 static void clear_exec_queue_pending_tdr_exit(struct xe_exec_queue *q) 266 265 { 267 266 atomic_and(~EXEC_QUEUE_STATE_PENDING_TDR_EXIT, &q->guc->state); 267 + } 268 + 269 + static bool exec_queue_idle_skip_suspend(struct xe_exec_queue *q) 270 + { 271 + return atomic_read(&q->guc->state) & EXEC_QUEUE_STATE_IDLE_SKIP_SUSPEND; 272 + } 273 + 274 + static void set_exec_queue_idle_skip_suspend(struct xe_exec_queue *q) 275 + { 276 + atomic_or(EXEC_QUEUE_STATE_IDLE_SKIP_SUSPEND, &q->guc->state); 277 + } 278 + 279 + static void clear_exec_queue_idle_skip_suspend(struct xe_exec_queue *q) 280 + { 281 + atomic_and(~EXEC_QUEUE_STATE_IDLE_SKIP_SUSPEND, &q->guc->state); 268 282 } 269 283 270 284 static bool exec_queue_killed_or_banned_or_wedged(struct xe_exec_queue *q) ··· 1134 1118 if (!job->restore_replay || job->last_replay) { 1135 1119 if (xe_exec_queue_is_parallel(q)) 1136 1120 wq_item_append(q); 1137 - else 1121 + else if (!exec_queue_idle_skip_suspend(q)) 1138 1122 xe_lrc_set_ring_tail(lrc, lrc->ring.tail); 1139 1123 job->last_replay = false; 1140 1124 } ··· 1922 1906 { 1923 1907 struct xe_exec_queue *q = msg->private_data; 1924 1908 struct xe_guc *guc = exec_queue_to_guc(q); 1909 + bool idle_skip_suspend = xe_exec_queue_idle_skip_suspend(q); 1925 1910 1926 - if (guc_exec_queue_allowed_to_change_state(q) && !exec_queue_suspended(q) && 1927 - exec_queue_enabled(q)) { 1911 + if (!idle_skip_suspend && guc_exec_queue_allowed_to_change_state(q) && 1912 + !exec_queue_suspended(q) && exec_queue_enabled(q)) { 1928 1913 wait_event(guc->ct.wq, vf_recovery(guc) || 1929 1914 ((q->guc->resume_time != RESUME_PENDING || 1930 1915 xe_guc_read_stopped(guc)) && !exec_queue_pending_disable(q))); ··· 1944 1927 disable_scheduling(q, false); 1945 1928 } 1946 1929 } else if (q->guc->suspend_pending) { 1930 + if (idle_skip_suspend) 1931 + set_exec_queue_idle_skip_suspend(q); 1947 1932 set_exec_queue_suspended(q); 1948 1933 suspend_fence_signal(q); 1949 1934 } 1935 + } 1936 + 1937 + static void sched_context(struct xe_exec_queue *q) 1938 + { 1939 + struct xe_guc *guc = exec_queue_to_guc(q); 1940 + struct xe_lrc *lrc = q->lrc[0]; 1941 + u32 action[] = { 1942 + XE_GUC_ACTION_SCHED_CONTEXT, 1943 + q->guc->id, 1944 + }; 1945 + 1946 + xe_gt_assert(guc_to_gt(guc), !xe_exec_queue_is_parallel(q)); 1947 + xe_gt_assert(guc_to_gt(guc), !exec_queue_destroyed(q)); 1948 + xe_gt_assert(guc_to_gt(guc), exec_queue_registered(q)); 1949 + xe_gt_assert(guc_to_gt(guc), !exec_queue_pending_disable(q)); 1950 + 1951 + trace_xe_exec_queue_submit(q); 1952 + 1953 + xe_lrc_set_ring_tail(lrc, lrc->ring.tail); 1954 + xe_guc_ct_send(&guc->ct, action, ARRAY_SIZE(action), 0, 0); 1950 1955 } 1951 1956 1952 1957 static void __guc_exec_queue_process_msg_resume(struct xe_sched_msg *msg) ··· 1978 1939 if (guc_exec_queue_allowed_to_change_state(q)) { 1979 1940 clear_exec_queue_suspended(q); 1980 1941 if (!exec_queue_enabled(q)) { 1942 + if (exec_queue_idle_skip_suspend(q)) { 1943 + struct xe_lrc *lrc = q->lrc[0]; 1944 + 1945 + clear_exec_queue_idle_skip_suspend(q); 1946 + xe_lrc_set_ring_tail(lrc, lrc->ring.tail); 1947 + } 1981 1948 q->guc->resume_time = RESUME_PENDING; 1982 1949 set_exec_queue_pending_resume(q); 1983 1950 enable_scheduling(q); 1951 + } else if (exec_queue_idle_skip_suspend(q)) { 1952 + clear_exec_queue_idle_skip_suspend(q); 1953 + sched_context(q); 1984 1954 } 1985 1955 } else { 1986 1956 clear_exec_queue_suspended(q); 1957 + clear_exec_queue_idle_skip_suspend(q); 1987 1958 } 1988 1959 } 1989 1960
+1 -1
drivers/gpu/drm/xe/xe_hw_engine_group.c
··· 205 205 continue; 206 206 207 207 xe_gt_stats_incr(q->gt, XE_GT_STATS_ID_HW_ENGINE_GROUP_SUSPEND_LR_QUEUE_COUNT, 1); 208 - need_resume = true; 208 + need_resume |= !xe_exec_queue_idle_skip_suspend(q); 209 209 q->ops->suspend(q); 210 210 } 211 211