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: Wrappers for setting and getting LRC references

There is a small but non-zero chance that VF post migration fixups
are running on an exec queue during teardown. The chances are
decreased by starting the teardown by releasing guc_id, but remain
non-zero. On the other hand the sync between fixups and EQ creation
(wait_valid_ggtt) drastically increases the chance for such parallel
teardown if queue creation error path is entered (err_lrc label).

The exec queue itself is not going to cause an issue, but LRCs have
a small chance of getting freed during the fixups.

Creating a setter and a getter makes it easier to protect the fixup
operations with a lock. For other driver activities, the original
access method (without any protection) can still be used.

v2: Separate lock, only for LRCs. Kerneldoc fixes. Subject tag fix.

Signed-off-by: Tomasz Lis <tomasz.lis@intel.com>
Reviewed-by: Matthew Brost <matthew.brost@intel.com>
Signed-off-by: Michal Wajdeczko <michal.wajdeczko@intel.com>
Link: https://patch.msgid.link/20260226212701.2937065-3-tomasz.lis@intel.com

authored by

Tomasz Lis and committed by
Michal Wajdeczko
ec172c7b 393e5fea

+60 -19
+54 -19
drivers/gpu/drm/xe/xe_exec_queue.c
··· 231 231 INIT_LIST_HEAD(&q->hw_engine_group_link); 232 232 INIT_LIST_HEAD(&q->pxp.link); 233 233 spin_lock_init(&q->multi_queue.lock); 234 + spin_lock_init(&q->lrc_lookup_lock); 234 235 q->multi_queue.priority = XE_MULTI_QUEUE_PRIORITY_NORMAL; 235 236 236 237 q->sched_props.timeslice_us = hwe->eclass->sched_props.timeslice_us; ··· 269 268 } 270 269 271 270 return q; 271 + } 272 + 273 + static void xe_exec_queue_set_lrc(struct xe_exec_queue *q, struct xe_lrc *lrc, u16 idx) 274 + { 275 + xe_assert(gt_to_xe(q->gt), idx < q->width); 276 + 277 + scoped_guard(spinlock, &q->lrc_lookup_lock) 278 + q->lrc[idx] = lrc; 279 + } 280 + 281 + /** 282 + * xe_exec_queue_get_lrc() - Get the LRC from exec queue. 283 + * @q: The exec queue instance. 284 + * @idx: Index within multi-LRC array. 285 + * 286 + * Retrieves LRC of given index for the exec queue under lock 287 + * and takes reference. 288 + * 289 + * Return: Pointer to LRC on success, error on failure, NULL on 290 + * lookup failure. 291 + */ 292 + struct xe_lrc *xe_exec_queue_get_lrc(struct xe_exec_queue *q, u16 idx) 293 + { 294 + struct xe_lrc *lrc; 295 + 296 + xe_assert(gt_to_xe(q->gt), idx < q->width); 297 + 298 + scoped_guard(spinlock, &q->lrc_lookup_lock) { 299 + lrc = q->lrc[idx]; 300 + if (lrc) 301 + xe_lrc_get(lrc); 302 + } 303 + 304 + return lrc; 305 + } 306 + 307 + /** 308 + * xe_exec_queue_lrc() - Get the LRC from exec queue. 309 + * @q: The exec queue instance. 310 + * 311 + * Retrieves the primary LRC for the exec queue. Note that this function 312 + * returns only the first LRC instance, even when multiple parallel LRCs 313 + * are configured. This function does not increment reference count, 314 + * so the reference can be just forgotten after use. 315 + * 316 + * Return: Pointer to LRC on success, error on failure 317 + */ 318 + struct xe_lrc *xe_exec_queue_lrc(struct xe_exec_queue *q) 319 + { 320 + return q->lrc[0]; 272 321 } 273 322 274 323 static void __xe_exec_queue_fini(struct xe_exec_queue *q) ··· 378 327 goto err_lrc; 379 328 } 380 329 381 - /* Pairs with READ_ONCE to xe_exec_queue_contexts_hwsp_rebase */ 382 - WRITE_ONCE(q->lrc[i], lrc); 330 + xe_exec_queue_set_lrc(q, lrc, i); 383 331 } 384 332 385 333 return 0; ··· 1344 1294 } 1345 1295 1346 1296 /** 1347 - * xe_exec_queue_lrc() - Get the LRC from exec queue. 1348 - * @q: The exec_queue. 1349 - * 1350 - * Retrieves the primary LRC for the exec queue. Note that this function 1351 - * returns only the first LRC instance, even when multiple parallel LRCs 1352 - * are configured. 1353 - * 1354 - * Return: Pointer to LRC on success, error on failure 1355 - */ 1356 - struct xe_lrc *xe_exec_queue_lrc(struct xe_exec_queue *q) 1357 - { 1358 - return q->lrc[0]; 1359 - } 1360 - 1361 - /** 1362 1297 * xe_exec_queue_is_lr() - Whether an exec_queue is long-running 1363 1298 * @q: The exec_queue 1364 1299 * ··· 1702 1667 for (i = 0; i < q->width; ++i) { 1703 1668 struct xe_lrc *lrc; 1704 1669 1705 - /* Pairs with WRITE_ONCE in __xe_exec_queue_init */ 1706 - lrc = READ_ONCE(q->lrc[i]); 1670 + lrc = xe_exec_queue_get_lrc(q, i); 1707 1671 if (!lrc) 1708 1672 continue; 1709 1673 1710 1674 xe_lrc_update_memirq_regs_with_address(lrc, q->hwe, scratch); 1711 1675 xe_lrc_update_hwctx_regs_with_address(lrc); 1712 1676 err = xe_lrc_setup_wa_bb_with_scratch(lrc, q->hwe, scratch); 1677 + xe_lrc_put(lrc); 1713 1678 if (err) 1714 1679 break; 1715 1680 }
+1
drivers/gpu/drm/xe/xe_exec_queue.h
··· 160 160 int xe_exec_queue_contexts_hwsp_rebase(struct xe_exec_queue *q, void *scratch); 161 161 162 162 struct xe_lrc *xe_exec_queue_lrc(struct xe_exec_queue *q); 163 + struct xe_lrc *xe_exec_queue_get_lrc(struct xe_exec_queue *q, u16 idx); 163 164 164 165 /** 165 166 * xe_exec_queue_idle_skip_suspend() - Can exec queue skip suspend
+5
drivers/gpu/drm/xe/xe_exec_queue_types.h
··· 257 257 u64 tlb_flush_seqno; 258 258 /** @hw_engine_group_link: link into exec queues in the same hw engine group */ 259 259 struct list_head hw_engine_group_link; 260 + /** 261 + * @lrc_lookup_lock: Lock for protecting lrc array access. Only used when 262 + * running in parallel to queue creation is possible. 263 + */ 264 + spinlock_t lrc_lookup_lock; 260 265 /** @lrc: logical ring context for this exec queue */ 261 266 struct xe_lrc *lrc[] __counted_by(width); 262 267 };