diff --git a/drivers/gpu/drm/xe/xe_guc_ct.c b/drivers/gpu/drm/xe/xe_guc_ct.c index 5c393aa29de3..da5ce97484b8 100644 --- a/drivers/gpu/drm/xe/xe_guc_ct.c +++ b/drivers/gpu/drm/xe/xe_guc_ct.c @@ -1290,11 +1290,23 @@ int xe_guc_ct_send(struct xe_guc_ct *ct, const u32 *action, u32 len, * @ct: GuC CT object * @action: payload dwords (HxG header dword is expected at @action[-1]) * @len: number of payload dwords in @action + * @g2h_len: G2H response space to reserve in dwords, or 0 + * @num_g2h: number of G2H messages expected, or 0 * @defer_flush: defer publishing/doorbell for batching * * Sends a single H2G message to the GuC CT buffer while the caller already * holds @ct->lock. * + * Callers that expect the GuC to reply with a G2H message must reserve the + * matching credit via @g2h_len / @num_g2h. The G2H receive path releases that + * credit unconditionally when the reply arrives, so failing to reserve it here + * corrupts the G2H accounting and kills the CT channel. + * + * Reserving G2H credit may wait for, and process, outstanding G2H messages, so + * this must not be called with a non-zero @g2h_len from a G2H handler. Handlers + * should use xe_guc_ct_send_g2h_handler(), with any reply credit reserved up + * front by the H2G that triggered the handler. + * * If @defer_flush is false, the function completes the submission immediately: * it makes the payload visible to the device, updates the H2G descriptor and * rings the GuC doorbell. @@ -1312,11 +1324,12 @@ int xe_guc_ct_send(struct xe_guc_ct *ct, const u32 *action, u32 len, * Must be called with @ct->lock held. */ int xe_guc_ct_send_locked(struct xe_guc_ct *ct, const u32 *action, u32 len, - bool defer_flush) + u32 g2h_len, u32 num_g2h, bool defer_flush) { int ret; - ret = guc_ct_send_locked(ct, action, len, 0, 0, NULL, defer_flush); + ret = guc_ct_send_locked(ct, action, len, g2h_len, num_g2h, NULL, + defer_flush); if (ret == -EDEADLK) kick_reset(ct); diff --git a/drivers/gpu/drm/xe/xe_guc_ct.h b/drivers/gpu/drm/xe/xe_guc_ct.h index 3ddc665ab84a..e2a33249d65d 100644 --- a/drivers/gpu/drm/xe/xe_guc_ct.h +++ b/drivers/gpu/drm/xe/xe_guc_ct.h @@ -56,7 +56,7 @@ static inline void xe_guc_ct_irq_handler(struct xe_guc_ct *ct) int xe_guc_ct_send(struct xe_guc_ct *ct, const u32 *action, u32 len, u32 g2h_len, u32 num_g2h); int xe_guc_ct_send_locked(struct xe_guc_ct *ct, const u32 *action, u32 len, - bool defer_flush); + u32 g2h_len, u32 num_g2h, bool defer_flush); int xe_guc_ct_send_recv(struct xe_guc_ct *ct, const u32 *action, u32 len, u32 *response_buffer); static inline int diff --git a/drivers/gpu/drm/xe/xe_guc_pagefault.c b/drivers/gpu/drm/xe/xe_guc_pagefault.c index df237fd40551..6b48550e7579 100644 --- a/drivers/gpu/drm/xe/xe_guc_pagefault.c +++ b/drivers/gpu/drm/xe/xe_guc_pagefault.c @@ -55,7 +55,8 @@ static void guc_ack_fault(struct xe_pagefault *pf, int err) bool write_only = guc->pagefault_ack_counter++ & (XE_GUC_PAGEFAULT_FLUSH_PERIOD - 1); - xe_guc_ct_send_locked(&guc->ct, action, ARRAY_SIZE(action), + /* Pagefault acks are fire-and-forget, no G2H reply expected. */ + xe_guc_ct_send_locked(&guc->ct, action, ARRAY_SIZE(action), 0, 0, write_only); }