From: "Tales A. Mendonça" <talesam@gmail.com>
To: intel-xe@lists.freedesktop.org
Cc: dri-devel@lists.freedesktop.org, matthew.brost@intel.com,
thomas.hellstrom@linux.intel.com, rodrigo.vivi@intel.com,
"Tales A. Mendonça" <talesam@gmail.com>
Subject: [PATCH v1 3/4] drm/xe/guc/ct: Queue G2H worker before flushing it in timeout paths
Date: Tue, 21 Jul 2026 21:46:53 -0300 [thread overview]
Message-ID: <20260722004654.744249-4-talesam@gmail.com> (raw)
In-Reply-To: <20260722004654.744249-1-talesam@gmail.com>
Timeout-recovery paths flush the G2H worker to pick up a response that
may have been posted by the GuC but not yet processed:
- guc_ct_send_recv() after the 1s wait for a G2H response fails
- the TLB invalidation backend's .flush() hook, called by
xe_tlb_inval_fence_timeout() before declaring a fence timed out
However flush_work() on a work item that is neither queued nor running
is a no-op. If the GUC2HOST interrupt for the response was lost or
coalesced, the G2H worker was never queued: the flush does not read the
G2H CTB and the response sits there unprocessed until an unrelated G2H
interrupt arrives. For TLB invalidations this results in
TLB invalidation fence timeout, seqno=N recv=N-1
with the fence force-signalled with -ETIME even though the ack may
already be present in the CTB. Observed sporadically on ARL-H under CPU
load, always with recv == seqno - 1 and self-recovering on the next G2H
interrupt, which is consistent with a lost wakeup rather than a
GuC-side failure.
Add xe_guc_ct_flush_g2h(), which queues the worker before flushing it,
guaranteeing the flush always drains the CTB, and use it in both
timeout paths. A spurious worker run is safe: g2h_read() returns no
data under fast_lock, and receive_g2h() copes with runtime-PM state and
disabled CT communication.
After this change the fence-timeout error only fires when the ack is
genuinely absent from the CTB, making the message a reliable indicator
of a GuC-side stall.
Signed-off-by: Tales A. Mendonça <talesam@gmail.com>
---
drivers/gpu/drm/xe/xe_guc_ct.c | 23 ++++++++++++++++++++++-
drivers/gpu/drm/xe/xe_guc_ct.h | 1 +
drivers/gpu/drm/xe/xe_guc_tlb_inval.c | 2 +-
3 files changed, 24 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/xe/xe_guc_ct.c b/drivers/gpu/drm/xe/xe_guc_ct.c
index fe70c0fd85c..11a05c2b8c7 100644
--- a/drivers/gpu/drm/xe/xe_guc_ct.c
+++ b/drivers/gpu/drm/xe/xe_guc_ct.c
@@ -1377,7 +1377,7 @@ static int guc_ct_send_recv(struct xe_guc_ct *ct, const u32 *action, u32 len,
wait_again:
ret = wait_event_timeout(ct->g2h_fence_wq, READ_ONCE(g2h_fence.done), HZ);
if (!ret) {
- LNL_FLUSH_WORK(&ct->g2h_worker);
+ xe_guc_ct_flush_g2h(ct);
if (READ_ONCE(g2h_fence.done)) {
xe_gt_warn(gt, "G2H fence %u, action %04x, done\n",
g2h_fence.seqno, action[0]);
@@ -2046,6 +2046,27 @@ static void g2h_worker_func(struct work_struct *w)
receive_g2h(ct);
}
+/**
+ * xe_guc_ct_flush_g2h() - Force processing of pending G2H messages
+ * @ct: GuC CT object
+ *
+ * The GUC2HOST interrupt for a G2H message may be lost or coalesced. When
+ * that happens the G2H worker is never queued and flushing it is a no-op
+ * that does not read the G2H CTB, leaving messages the GuC has already
+ * posted unprocessed until the next interrupt arrives. Queue the worker
+ * before flushing it so the flush always drains the G2H CTB. A spurious
+ * worker run is safe: it returns without side effects if the CTB is empty
+ * or CT communication is disabled.
+ */
+void xe_guc_ct_flush_g2h(struct xe_guc_ct *ct)
+{
+ if (!xe_guc_ct_enabled(ct))
+ return;
+
+ queue_work(ct->g2h_wq, &ct->g2h_worker);
+ flush_work(&ct->g2h_worker);
+}
+
static struct xe_guc_ct_snapshot *guc_ct_snapshot_alloc(struct xe_guc_ct *ct, bool atomic,
bool want_ctb)
{
diff --git a/drivers/gpu/drm/xe/xe_guc_ct.h b/drivers/gpu/drm/xe/xe_guc_ct.h
index 767365a33de..4e0338953f1 100644
--- a/drivers/gpu/drm/xe/xe_guc_ct.h
+++ b/drivers/gpu/drm/xe/xe_guc_ct.h
@@ -22,6 +22,7 @@ void xe_guc_ct_runtime_suspend(struct xe_guc_ct *ct);
void xe_guc_ct_stop(struct xe_guc_ct *ct);
void xe_guc_ct_flush_and_stop(struct xe_guc_ct *ct);
void xe_guc_ct_fast_path(struct xe_guc_ct *ct);
+void xe_guc_ct_flush_g2h(struct xe_guc_ct *ct);
struct xe_guc_ct_snapshot *xe_guc_ct_snapshot_capture(struct xe_guc_ct *ct);
void xe_guc_ct_snapshot_print(struct xe_guc_ct_snapshot *snapshot, struct drm_printer *p);
diff --git a/drivers/gpu/drm/xe/xe_guc_tlb_inval.c b/drivers/gpu/drm/xe/xe_guc_tlb_inval.c
index 046d0655122..91960dc4ba9 100644
--- a/drivers/gpu/drm/xe/xe_guc_tlb_inval.c
+++ b/drivers/gpu/drm/xe/xe_guc_tlb_inval.c
@@ -327,7 +327,7 @@ static void tlb_inval_flush(struct xe_tlb_inval *tlb_inval)
{
struct xe_guc *guc = tlb_inval->private;
- LNL_FLUSH_WORK(&guc->ct.g2h_worker);
+ xe_guc_ct_flush_g2h(&guc->ct);
}
static long tlb_inval_timeout_delay(struct xe_tlb_inval *tlb_inval)
--
2.55.0
next prev parent reply other threads:[~2026-07-22 13:42 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-22 0:46 [PATCH v1 0/4] drm/xe: MCR semaphore and TLB invalidation timeout fixes for ARL Tales A. Mendonça
2026-07-22 0:46 ` [PATCH v1 1/4] drm/xe/mcr: Keep GT forcewake during MCR steering Tales A. Mendonça
2026-07-22 14:02 ` sashiko-bot
2026-07-22 17:45 ` Tales A. Mendonça
2026-07-22 18:10 ` Matt Roper
2026-07-22 18:39 ` Tales A. Mendonça
2026-07-22 0:46 ` [PATCH v1 2/4] drm/xe/mcr: Sanitize steering semaphore on GT resume Tales A. Mendonça
2026-07-22 13:57 ` sashiko-bot
2026-07-22 17:47 ` Tales A. Mendonça
2026-07-22 0:46 ` Tales A. Mendonça [this message]
2026-07-22 14:07 ` [PATCH v1 3/4] drm/xe/guc/ct: Queue G2H worker before flushing it in timeout paths sashiko-bot
2026-07-22 17:48 ` Tales A. Mendonça
2026-07-22 0:46 ` [PATCH v1 4/4] drm/xe: Raise hw_tlb_timeout to cover observed GuC ack latency Tales A. Mendonça
2026-07-22 17:27 ` ✗ LGCI.VerificationFailed: failure for drm/xe: MCR semaphore and TLB invalidation timeout fixes for ARL Patchwork
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260722004654.744249-4-talesam@gmail.com \
--to=talesam@gmail.com \
--cc=dri-devel@lists.freedesktop.org \
--cc=intel-xe@lists.freedesktop.org \
--cc=matthew.brost@intel.com \
--cc=rodrigo.vivi@intel.com \
--cc=thomas.hellstrom@linux.intel.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.