Intel-XE Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: Daniele Ceraolo Spurio <daniele.ceraolospurio@intel.com>
To: Michal Wajdeczko <michal.wajdeczko@intel.com>,
	<intel-xe@lists.freedesktop.org>
Cc: Aravind Iddamsetty <aravind.iddamsetty@intel.com>,
	Mallesh Koujalagi <mallesh.koujalagi@intel.com>,
	Alan Previn Teres Alexis <alan.previn.teres.alexis@intel.com>,
	Julia Filipchuk <julia.filipchuk@intel.com>
Subject: Re: [PATCH 3/3] drm/xe/guc: Report errors that cause a CT shutdown using SIGID
Date: Thu, 27 Aug 2026 14:33:21 -0700	[thread overview]
Message-ID: <b3f36afd-c702-4359-bac6-3e5eec11aa66@intel.com> (raw)
In-Reply-To: <c88d3c1e-4b46-41b4-be7d-829b12e2e18d@intel.com>



On 8/27/2026 7:34 AM, Michal Wajdeczko wrote:
>
> On 8/27/2026 2:28 AM, Daniele Ceraolo Spurio wrote:
>> Convert any errors that can cause the CT to be declared as dead to
>> use the xe_log_err() helper. Errors that are escalated to the callers
>> are left for the caller to report with SIGID if needed.
>>
>> Signed-off-by: Daniele Ceraolo Spurio <daniele.ceraolospurio@intel.com>
>> Cc: Michal Wajdeczko <michal.wajdeczko@intel.com>
>> Cc: Aravind Iddamsetty <aravind.iddamsetty@intel.com>
>> Cc: Mallesh Koujalagi <mallesh.koujalagi@intel.com>
>> Cc: Alan Previn Teres Alexis <alan.previn.teres.alexis@intel.com>
>> Cc: Julia Filipchuk <julia.filipchuk@intel.com>
>> ---
>>   drivers/gpu/drm/xe/xe_guc_ct.c | 91 +++++++++++++++++++---------------
>>   1 file changed, 51 insertions(+), 40 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/xe/xe_guc_ct.c b/drivers/gpu/drm/xe/xe_guc_ct.c
>> index 5c4733da385c..4efaf2d24c3e 100644
>> --- a/drivers/gpu/drm/xe/xe_guc_ct.c
>> +++ b/drivers/gpu/drm/xe/xe_guc_ct.c
>> @@ -30,6 +30,7 @@
>>   #include "xe_guc_relay.h"
>>   #include "xe_guc_submit.h"
>>   #include "xe_guc_tlb_inval.h"
>> +#include "xe_log.h"
>>   #include "xe_map.h"
>>   #include "xe_page_reclaim.h"
>>   #include "xe_pm.h"
>> @@ -679,7 +680,7 @@ static int __xe_guc_ct_start(struct xe_guc_ct *ct, bool needs_register)
>>   	return 0;
>>   
>>   err_out:
>> -	xe_gt_err(gt, "Failed to enable GuC CT (%pe)\n", ERR_PTR(err));
>> +	xe_log_err(gt, GUC, err, "Failed to enable CT\n");
>>   	CT_DEAD(ct, NULL, SETUP);
>>   
>>   	return err;
>> @@ -803,8 +804,9 @@ static bool h2g_has_room(struct xe_guc_ct *ct, u32 cmd_len)
>>   
>>   			desc_write(xe, h2g, status, desc_status | GUC_CTB_STATUS_OVERFLOW);
>>   
>> -			xe_gt_err(ct_to_gt(ct), "CT: invalid head offset %u >= %u)\n",
>> -				  h2g->info.head, h2g->info.size);
>> +			xe_log_err(ct_to_gt(ct), GUC, -EPROTO,
>> +				   "CT: invalid head offset %u >= %u)\n",
>> +				   h2g->info.head, h2g->info.size);
> nit: we usually use -EPROTO to report mismatch in the messages
> while here we have corrupted descriptor, so maybe we can use
> something else, like:
>
> #define	ENFILE		23	/* File table overflow */
> #define	ESPIPE		29	/* Illegal seek */
> #define	EPIPE		32	/* Broken pipe */
> #define	EILSEQ		84	/* Illegal byte sequence */
> #define	EUCLEAN		117	/* Structure needs cleaning */
>
>>   			CT_DEAD(ct, h2g, H2G_HAS_ROOM);
>>   			return false;
>>   		}
>> @@ -873,12 +875,13 @@ static void __g2h_release_space(struct xe_guc_ct *ct, u32 g2h_len)
>>   	bad |= !ct->g2h_outstanding;
>>   
>>   	if (bad) {
>> -		xe_gt_err(ct_to_gt(ct), "Invalid G2H release: %d + %d vs %d - %d -> %d vs %d, outstanding = %d!\n",
>> -			  ct->ctbs.g2h.info.space, g2h_len,
>> -			  ct->ctbs.g2h.info.size, ct->ctbs.g2h.info.resv_space,
>> -			  ct->ctbs.g2h.info.space + g2h_len,
>> -			  ct->ctbs.g2h.info.size - ct->ctbs.g2h.info.resv_space,
>> -			  ct->g2h_outstanding);
>> +		xe_log_err(ct_to_gt(ct), GUC, -EPROTO,
> hmm, here the "bad" flag is more an indication of our (xe) miscalculation,
> not something that FW did wrong, so -EPROTO seems wrong, maybe
>
> #define	ETOOMANYREFS	109	/* Too many references: cannot splice */
>> +			   "Invalid G2H release: %d + %d vs %d - %d -> %d vs %d, outstanding = %d!\n",
>> +			   ct->ctbs.g2h.info.space, g2h_len,
>> +			   ct->ctbs.g2h.info.size, ct->ctbs.g2h.info.resv_space,
>> +			   ct->ctbs.g2h.info.space + g2h_len,
>> +			   ct->ctbs.g2h.info.size - ct->ctbs.g2h.info.resv_space,
>> +			   ct->g2h_outstanding);
>>   		CT_DEAD(ct, &ct->ctbs.g2h, G2H_RELEASE);
>>   		return;
>>   	}
>> @@ -961,21 +964,24 @@ static int h2g_write(struct xe_guc_ct *ct, const u32 *action, u32 len,
>>   
>>   		desc_status = desc_read(xe, h2g, status);
>>   		if (desc_status) {
>> -			xe_gt_err(gt, "CT write: non-zero status: %u\n", desc_status);
>> +			xe_log_err(gt, GUC, -EPROTO,
>> +				   "CT write: non-zero status: %u\n", desc_status);
>>   			goto corrupted;
>>   		}
>>   
>>   		if (tail > h2g->info.size) {
>>   			desc_write(xe, h2g, status, desc_status | GUC_CTB_STATUS_OVERFLOW);
>> -			xe_gt_err(gt, "CT write: tail out of range: %u vs %u\n",
>> -				  tail, h2g->info.size);
>> +			xe_log_err(gt, GUC, -EPROTO,
>> +				   "CT write: tail out of range: %u vs %u\n",
>> +				   tail, h2g->info.size);
>>   			goto corrupted;
>>   		}
>>   
>>   		if (desc_head >= h2g->info.size) {
>>   			desc_write(xe, h2g, status, desc_status | GUC_CTB_STATUS_OVERFLOW);
>> -			xe_gt_err(gt, "CT write: invalid head offset %u >= %u)\n",
>> -				  desc_head, h2g->info.size);
>> +			xe_log_err(gt, GUC, -EPROTO,
> as this indicates that FW found an error in CTB, maybe:
>
> #define	EPIPE		32	/* Broken pipe */
>
>> +				   "CT write: invalid head offset %u >= %u)\n",
>> +				   desc_head, h2g->info.size);
>>   			goto corrupted;
>>   		}
>>   	}
>> @@ -1220,7 +1226,7 @@ static int guc_ct_send_locked(struct xe_guc_ct *ct, const u32 *action, u32 len,
>>   	return ret;
>>   
>>   broken:
>> -	xe_gt_err(gt, "No forward process on H2G, reset required\n");
>> +	xe_log_err(gt, GUC, -EDEADLK, "No forward process on H2G, reset required\n");
>>   	CT_DEAD(ct, &ct->ctbs.h2g, DEADLOCK);
>>   
>>   	return -EDEADLK;
>> @@ -1558,11 +1564,11 @@ static int guc_crash_process_msg(struct xe_guc_ct *ct, u32 action)
>>   	struct xe_gt *gt = ct_to_gt(ct);
>>   
>>   	if (action == XE_GUC_ACTION_NOTIFY_CRASH_DUMP_POSTED)
>> -		xe_gt_err(gt, "GuC Crash dump notification\n");
>> +		xe_log_err(gt, GUC, -EPROTO, "GuC Crash dump notification\n");
>>   	else if (action == XE_GUC_ACTION_NOTIFY_EXCEPTION)
>> -		xe_gt_err(gt, "GuC Exception notification\n");
>> +		xe_log_err(gt, GUC, -EPROTO, "GuC Exception notification\n");
>>   	else
>> -		xe_gt_err(gt, "Unknown GuC crash notification: 0x%04X\n", action);
>> +		xe_log_err(gt, GUC, -EPROTO, "Unknown GuC crash notification: 0x%04X\n", action);
> maybe crashes should be identified as one of:
>
> #define	ENETDOWN	100	/* Network is down */
> #define	ENETUNREACH	101	/* Network is unreachable */
> #define	EHOSTDOWN	112	/* Host is down */
>
>>   
>>   	CT_DEAD(ct, NULL, CRASH);
>>   
>> @@ -1592,13 +1598,15 @@ static int parse_g2h_response(struct xe_guc_ct *ct, u32 *msg, u32 len)
>>   	 */
>>   	if (fence & CT_SEQNO_UNTRACKED) {
>>   		if (type == GUC_HXG_TYPE_RESPONSE_FAILURE)
>> -			xe_gt_err(gt, "FAST_REQ H2G fence 0x%x failed! e=0x%x, h=%u\n",
>> -				  fence,
>> -				  FIELD_GET(GUC_HXG_FAILURE_MSG_0_ERROR, hxg[0]),
>> -				  FIELD_GET(GUC_HXG_FAILURE_MSG_0_HINT, hxg[0]));
>> +			xe_log_err(gt, GUC, -EPROTO,
> FAILURE response is a valid message, maybe:
>
> #define	EBADE		52	/* Invalid exchange */
>
>> +				   "FAST_REQ H2G fence 0x%x failed! e=0x%x, h=%u\n",
>> +				   fence,
>> +				   FIELD_GET(GUC_HXG_FAILURE_MSG_0_ERROR, hxg[0]),
>> +				   FIELD_GET(GUC_HXG_FAILURE_MSG_0_HINT, hxg[0]));
>>   		else
>> -			xe_gt_err(gt, "unexpected response %u for FAST_REQ H2G fence 0x%x!\n",
>> -				  type, fence);
>> +			xe_log_err(gt, GUC, -EPROTO,
>> +				   "unexpected response %u for FAST_REQ H2G fence 0x%x!\n",
>> +				    type, fence);
>>   
>>   		fast_req_report(ct, fence);
>>   
>> @@ -1674,8 +1682,9 @@ static int parse_g2h_msg(struct xe_guc_ct *ct, u32 *msg, u32 len)
>>   
>>   	origin = FIELD_GET(GUC_HXG_MSG_0_ORIGIN, hxg[0]);
>>   	if (unlikely(origin != GUC_HXG_ORIGIN_GUC)) {
>> -		xe_gt_err(gt, "G2H channel broken on read, origin=%u, reset required\n",
>> -			  origin);
>> +		xe_log_err(gt, GUC, -EPROTO,
>> +			   "G2H channel broken on read, origin=%u, reset required\n",
> #define	EBADMSG		74	/* Not a data message */

For this one I can switch to EBADMSG  for the log, but the return value 
needs to stick to EPROTO because the value is returned all the way back 
to receive_g2h, which checks specifically for EPROTO or EOPNOTSUPP. 
Changing this flow to handle different error codes is out of scope of 
this series IMO.

>
>> +			   origin);
>>   		CT_DEAD(ct, &ct->ctbs.g2h, PARSE_G2H_ORIGIN);
>>   
>>   		return -EPROTO;
>> @@ -1693,8 +1702,9 @@ static int parse_g2h_msg(struct xe_guc_ct *ct, u32 *msg, u32 len)
>>   		ret = parse_g2h_response(ct, msg, len);
>>   		break;
>>   	default:
>> -		xe_gt_err(gt, "G2H channel broken on read, type=%u, reset required\n",
>> -			  type);
>> +		xe_log_err(gt, GUC, -EOPNOTSUPP,
>> +			   "G2H channel broken on read, type=%u, reset required\n",
> maybe this should say: "Unexpected message type %u" ?
> and since we rather do not expect new message types in CTBv1 then
> maybe this one should be actually -EPROTO ?

I think it's better to stick with EOPNOTSUPP, but I can reword the message.

>
>> +			   type);
>>   		CT_DEAD(ct, &ct->ctbs.g2h, PARSE_G2H_TYPE);
>>   
>>   		ret = -EOPNOTSUPP;
>> @@ -1792,8 +1802,8 @@ static int process_g2h_msg(struct xe_guc_ct *ct, u32 *msg, u32 len)
>>   	}
>>   
>>   	if (ret) {
>> -		xe_gt_err(gt, "G2H action %#04x failed (%pe) len %u msg %*ph\n",
>> -			  action, ERR_PTR(ret), hxg_len, (int)sizeof(u32) * hxg_len, hxg);
>> +		xe_log_err(gt, GUC, ret, "G2H action %#04x failed (%pe) len %u msg %*ph\n",
>> +			   action, ERR_PTR(ret), hxg_len, (int)sizeof(u32) * hxg_len, hxg);
> drop %pe as it will be already printed
>
>>   		CT_DEAD(ct, NULL, PROCESS_FAILED);
>>   	}
>>   
>> @@ -1840,7 +1850,7 @@ static int g2h_read(struct xe_guc_ct *ct, u32 *msg, bool fast_path)
>>   		}
>>   
>>   		if (desc_status) {
>> -			xe_gt_err(gt, "CT read: non-zero status: %u\n", desc_status);
>> +			xe_log_err(gt, GUC, -EIO, "CT read: non-zero status: %u\n", desc_status);
> #define	EPIPE		32	/* Broken pipe */
>
>>   			goto corrupted;
>>   		}
>>   	}
>> @@ -1871,15 +1881,15 @@ static int g2h_read(struct xe_guc_ct *ct, u32 *msg, bool fast_path)
>>   
>>   		if (g2h->info.head > g2h->info.size) {
>>   			desc_write(xe, g2h, status, desc_status | GUC_CTB_STATUS_OVERFLOW);
>> -			xe_gt_err(gt, "CT read: head out of range: %u vs %u\n",
>> -				  g2h->info.head, g2h->info.size);
>> +			xe_log_err(gt, GUC, -EIO, "CT read: head out of range: %u vs %u\n",
>> +				   g2h->info.head, g2h->info.size);
> as before, one of:
>
> #define	ENFILE		23	/* File table overflow */
> #define	ESPIPE		29	/* Illegal seek */
> #define	EPIPE		32	/* Broken pipe */
> #define	EILSEQ		84	/* Illegal byte sequence */
> #define	EUCLEAN		117	/* Structure needs cleaning */
>
> maybe except EPIPE which we want to use to indicate that CTB error
> was already set earlier (likely by the GuC FW)

IMO grouping all cases where the CTB header is in a bad state (whether 
because the GuC signaled an error or because it wrote and invalid value) 
under EPIPE is cleaner. Having too many different error codes will just 
get confusing.

>
>>   			goto corrupted;
>>   		}
>>   
>>   		if (desc_tail >= g2h->info.size) {
>>   			desc_write(xe, g2h, status, desc_status | GUC_CTB_STATUS_OVERFLOW);
>> -			xe_gt_err(gt, "CT read: invalid tail offset %u >= %u)\n",
>> -				  desc_tail, g2h->info.size);
>> +			xe_log_err(gt, GUC, -EIO, "CT read: invalid tail offset %u >= %u)\n",
>> +				   desc_tail, g2h->info.size);
> ditto
>
>>   			goto corrupted;
>>   		}
>>   	}
>> @@ -1898,8 +1908,9 @@ static int g2h_read(struct xe_guc_ct *ct, u32 *msg, bool fast_path)
>>   			   sizeof(u32));
>>   	len = FIELD_GET(GUC_CTB_MSG_0_NUM_DWORDS, msg[0]) + GUC_CTB_MSG_MIN_LEN;
>>   	if (len > avail) {
>> -		xe_gt_err(gt, "G2H channel broken on read, avail=%d, len=%d, reset required\n",
>> -			  avail, len);
>> +		xe_log_err(gt, GUC, -EIO,
>> +			   "G2H channel broken on read, avail=%d, len=%d, reset required\n",
>> +			   avail, len);
> #define	ENODATA		61	/* No data available */
>
>>   		goto corrupted;
>>   	}
>>   
>> @@ -1981,8 +1992,8 @@ static void g2h_fast_path(struct xe_guc_ct *ct, u32 *msg, u32 len)
>>   	}
>>   
>>   	if (ret) {
>> -		xe_gt_err(gt, "G2H action 0x%04x failed (%pe)\n",
>> -			  action, ERR_PTR(ret));
>> +		xe_log_err(gt, GUC, ret, "G2H action 0x%04x failed (%pe)\n",
>> +			   action, ERR_PTR(ret));
> nit: you may use %#x
> drop %pe
>
>>   		CT_DEAD(ct, NULL, FAST_G2H);
>>   	}
>>   }
>> @@ -2080,7 +2091,7 @@ static void receive_g2h(struct xe_guc_ct *ct)
>>   		mutex_unlock(&ct->lock);
>>   
>>   		if (unlikely(ret == -EPROTO || ret == -EOPNOTSUPP)) {
>> -			xe_gt_err(ct_to_gt(ct), "CT dequeue failed: %d\n", ret);
>> +			xe_log_err(ct_to_gt(ct), GUC, ret, "CT dequeue failed: %d\n", ret);
> drop %d as we will already print ret using %pe
>
> also, maybe worth to mention "..., forcing GT reset" ?
>
>>   			CT_DEAD(ct, NULL, G2H_RECV);
> hmm, I'm pretty sure this is redundant as we already call CT_DEAD
> on every case where we report an error, can you double check?

There is at least one failure case in process_g2h_msg where we don't 
call CT_DEAD. If we want to rework this so that CT_DEAD is not called 
from here I believe it should be done separately.

Apart from the suggestions I have commented on, I am implementing all 
the other ones.

Daniele

>
>>   			kick_reset(ct);
>>   		}


  reply	other threads:[~2026-08-27 21:33 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-27  0:27 [PATCH 1/3] drm/xe/uc: Report DMA failure using SIGID Daniele Ceraolo Spurio
2026-08-27  0:28 ` [PATCH 2/3] drm/xe/guc: Report major GuC failures " Daniele Ceraolo Spurio
2026-08-27 11:47   ` Michal Wajdeczko
2026-08-27  0:28 ` [PATCH 3/3] drm/xe/guc: Report errors that cause a CT shutdown " Daniele Ceraolo Spurio
2026-08-27 14:34   ` Michal Wajdeczko
2026-08-27 21:33     ` Daniele Ceraolo Spurio [this message]
2026-08-27 22:41       ` Michal Wajdeczko
2026-08-27  0:36 ` ✓ CI.KUnit: success for series starting with [1/3] drm/xe/uc: Report DMA failure " Patchwork
2026-08-27  1:35 ` ✓ Xe.CI.BAT: " Patchwork
2026-08-27  2:39 ` ✓ Xe.CI.FULL: " Patchwork
2026-08-27 11:21 ` [PATCH 1/3] " Michal Wajdeczko

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=b3f36afd-c702-4359-bac6-3e5eec11aa66@intel.com \
    --to=daniele.ceraolospurio@intel.com \
    --cc=alan.previn.teres.alexis@intel.com \
    --cc=aravind.iddamsetty@intel.com \
    --cc=intel-xe@lists.freedesktop.org \
    --cc=julia.filipchuk@intel.com \
    --cc=mallesh.koujalagi@intel.com \
    --cc=michal.wajdeczko@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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox