Skip to content

Commit 9aff63c

Browse files
committed
drm/xe: Prep TLB invalidation fence before sending
It is a bit backwards to add a TLB invalidation fence to the pending list after issuing the invalidation. Perform this step before issuing the TLB invalidation in a helper function. v2: Make sure the seqno_lock mutex covers the send as well (Matt) Signed-off-by: Stuart Summers <stuart.summers@intel.com> Reviewed-by: Stuart Summers <stuart.summers@intel.com> Signed-off-by: Matthew Brost <matthew.brost@intel.com> Link: https://lore.kernel.org/r/20250826182911.392550-8-stuart.summers@intel.com
1 parent 1536623 commit 9aff63c

1 file changed

Lines changed: 55 additions & 54 deletions

File tree

drivers/gpu/drm/xe/xe_tlb_inval.c

Lines changed: 55 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -66,19 +66,19 @@ __inval_fence_signal(struct xe_device *xe, struct xe_tlb_inval_fence *fence)
6666
static void
6767
inval_fence_signal(struct xe_device *xe, struct xe_tlb_inval_fence *fence)
6868
{
69+
lockdep_assert_held(&fence->tlb_inval->pending_lock);
70+
6971
list_del(&fence->link);
7072
__inval_fence_signal(xe, fence);
7173
}
7274

73-
void xe_tlb_inval_fence_signal(struct xe_tlb_inval_fence *fence)
75+
static void
76+
inval_fence_signal_unlocked(struct xe_device *xe,
77+
struct xe_tlb_inval_fence *fence)
7478
{
75-
struct xe_gt *gt;
76-
77-
if (WARN_ON_ONCE(!fence->tlb_inval))
78-
return;
79-
80-
gt = fence->tlb_inval->private;
81-
__inval_fence_signal(gt_to_xe(gt), fence);
79+
spin_lock_irq(&fence->tlb_inval->pending_lock);
80+
inval_fence_signal(xe, fence);
81+
spin_unlock_irq(&fence->tlb_inval->pending_lock);
8282
}
8383

8484
static void xe_gt_tlb_fence_timeout(struct work_struct *work)
@@ -221,14 +221,10 @@ static bool tlb_inval_seqno_past(struct xe_gt *gt, int seqno)
221221
return seqno_recv >= seqno;
222222
}
223223

224-
static int send_tlb_inval(struct xe_guc *guc,
225-
struct xe_tlb_inval_fence *fence,
224+
static int send_tlb_inval(struct xe_guc *guc, struct xe_tlb_inval_fence *fence,
226225
u32 *action, int len)
227226
{
228227
struct xe_gt *gt = guc_to_gt(guc);
229-
struct xe_device *xe = gt_to_xe(gt);
230-
int seqno;
231-
int ret;
232228

233229
xe_gt_assert(gt, fence);
234230

@@ -238,47 +234,36 @@ static int send_tlb_inval(struct xe_guc *guc,
238234
* need to be updated.
239235
*/
240236

241-
mutex_lock(&gt->tlb_inval.seqno_lock);
242-
seqno = gt->tlb_inval.seqno;
243-
fence->seqno = seqno;
244-
trace_xe_tlb_inval_fence_send(xe, fence);
245-
action[1] = seqno;
246-
ret = xe_guc_ct_send(&guc->ct, action, len,
247-
G2H_LEN_DW_TLB_INVALIDATE, 1);
248-
if (!ret) {
249-
spin_lock_irq(&gt->tlb_inval.pending_lock);
250-
/*
251-
* We haven't actually published the TLB fence as per
252-
* pending_fences, but in theory our seqno could have already
253-
* been written as we acquired the pending_lock. In such a case
254-
* we can just go ahead and signal the fence here.
255-
*/
256-
if (tlb_inval_seqno_past(gt, seqno)) {
257-
__inval_fence_signal(xe, fence);
258-
} else {
259-
fence->inval_time = ktime_get();
260-
list_add_tail(&fence->link,
261-
&gt->tlb_inval.pending_fences);
262-
263-
if (list_is_singular(&gt->tlb_inval.pending_fences))
264-
queue_delayed_work(system_wq,
265-
&gt->tlb_inval.fence_tdr,
266-
tlb_timeout_jiffies(gt));
267-
}
268-
spin_unlock_irq(&gt->tlb_inval.pending_lock);
269-
} else {
270-
__inval_fence_signal(xe, fence);
271-
}
272-
if (!ret) {
273-
gt->tlb_inval.seqno = (gt->tlb_inval.seqno + 1) %
274-
TLB_INVALIDATION_SEQNO_MAX;
275-
if (!gt->tlb_inval.seqno)
276-
gt->tlb_inval.seqno = 1;
277-
}
278-
mutex_unlock(&gt->tlb_inval.seqno_lock);
279237
xe_gt_stats_incr(gt, XE_GT_STATS_ID_TLB_INVAL, 1);
238+
action[1] = fence->seqno;
280239

281-
return ret;
240+
return xe_guc_ct_send(&guc->ct, action, len,
241+
G2H_LEN_DW_TLB_INVALIDATE, 1);
242+
}
243+
244+
static void xe_tlb_inval_fence_prep(struct xe_tlb_inval_fence *fence)
245+
{
246+
struct xe_tlb_inval *tlb_inval = fence->tlb_inval;
247+
struct xe_gt *gt = tlb_inval->private;
248+
struct xe_device *xe = gt_to_xe(gt);
249+
250+
fence->seqno = tlb_inval->seqno;
251+
trace_xe_tlb_inval_fence_send(xe, fence);
252+
253+
spin_lock_irq(&tlb_inval->pending_lock);
254+
fence->inval_time = ktime_get();
255+
list_add_tail(&fence->link, &tlb_inval->pending_fences);
256+
257+
if (list_is_singular(&tlb_inval->pending_fences))
258+
queue_delayed_work(system_wq,
259+
&tlb_inval->fence_tdr,
260+
tlb_timeout_jiffies(gt));
261+
spin_unlock_irq(&tlb_inval->pending_lock);
262+
263+
tlb_inval->seqno = (tlb_inval->seqno + 1) %
264+
TLB_INVALIDATION_SEQNO_MAX;
265+
if (!tlb_inval->seqno)
266+
tlb_inval->seqno = 1;
282267
}
283268

284269
#define MAKE_INVAL_OP(type) ((type << XE_GUC_TLB_INVAL_TYPE_SHIFT) | \
@@ -306,7 +291,14 @@ static int xe_tlb_inval_guc(struct xe_gt *gt,
306291
};
307292
int ret;
308293

294+
mutex_lock(&gt->tlb_inval.seqno_lock);
295+
xe_tlb_inval_fence_prep(fence);
296+
309297
ret = send_tlb_inval(&gt->uc.guc, fence, action, ARRAY_SIZE(action));
298+
if (ret < 0)
299+
inval_fence_signal_unlocked(gt_to_xe(gt), fence);
300+
mutex_unlock(&gt->tlb_inval.seqno_lock);
301+
310302
/*
311303
* -ECANCELED indicates the CT is stopped for a GT reset. TLB caches
312304
* should be nuked on a GT reset so this error can be ignored.
@@ -433,7 +425,7 @@ int xe_tlb_inval_range(struct xe_tlb_inval *tlb_inval,
433425
#define MAX_TLB_INVALIDATION_LEN 7
434426
u32 action[MAX_TLB_INVALIDATION_LEN];
435427
u64 length = end - start;
436-
int len = 0;
428+
int len = 0, ret;
437429

438430
xe_gt_assert(gt, fence);
439431

@@ -494,7 +486,16 @@ int xe_tlb_inval_range(struct xe_tlb_inval *tlb_inval,
494486

495487
xe_gt_assert(gt, len <= MAX_TLB_INVALIDATION_LEN);
496488

497-
return send_tlb_inval(&gt->uc.guc, fence, action, len);
489+
mutex_lock(&gt->tlb_inval.seqno_lock);
490+
xe_tlb_inval_fence_prep(fence);
491+
492+
ret = send_tlb_inval(&gt->uc.guc, fence, action,
493+
ARRAY_SIZE(action));
494+
if (ret < 0)
495+
inval_fence_signal_unlocked(xe, fence);
496+
mutex_unlock(&gt->tlb_inval.seqno_lock);
497+
498+
return ret;
498499
}
499500

500501
/**

0 commit comments

Comments
 (0)