The functions intel_guc_send_busy_loop and ct_send can theoretically loop forever. In the former case, intel_guc_send_busy_loop can iterate forever if intel_guc_send_nb repeatedly returns -EBUSY. In the latter case, ct_send can loop forever if the guc-to-host or host-to-guc buffers get stuck in a full state.
Rework the sleep_period_ms values here to count the number of loops that have occurred and exit after 20. This lets both functions run for 10 minutes before escaping with -EBUSY (except in the former case if atomic execution is enabled, but 20 consecutive failures in that case should still be reported regardless). This also technically solves a static analysis issue wherein sleep_period_ms could overflow, but it would take over three weeks of perpetual sleeping on these functions to ever hit that overflow, so it's debatable whether this actually needed fixing or not. At any rate, it's better to exit early in the error case. Signed-off-by: Jonathan Cavitt <[email protected]> --- drivers/gpu/drm/i915/gt/uc/intel_guc.h | 10 +++++++--- drivers/gpu/drm/i915/gt/uc/intel_guc_ct.c | 8 +++++--- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc.h b/drivers/gpu/drm/i915/gt/uc/intel_guc.h index 053780f562c1..b4bf12193f75 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc.h +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc.h @@ -361,7 +361,7 @@ static inline int intel_guc_send_busy_loop(struct intel_guc *guc, bool loop) { int err; - unsigned int sleep_period_ms = 1; + unsigned int loop_count = 0; bool not_atomic = !in_atomic() && !irqs_disabled(); /* @@ -377,13 +377,17 @@ static inline int intel_guc_send_busy_loop(struct intel_guc *guc, retry: err = intel_guc_send_nb(guc, action, len, g2h_len_dw); if (unlikely(err == -EBUSY && loop)) { + if (loop_count >= 20) + return -EBUSY; + if (likely(not_atomic)) { - if (msleep_interruptible(sleep_period_ms)) + if (msleep_interruptible(1 << loop_count)) return -EINTR; - sleep_period_ms = sleep_period_ms << 1; } else { cpu_relax(); } + + loop_count++; goto retry; } diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_ct.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_ct.c index 8c4da526d461..e4a5697622c8 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_ct.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_ct.c @@ -716,7 +716,7 @@ static int ct_send(struct intel_guc_ct *ct, struct intel_guc_ct_buffer *ctb = &ct->ctbs.send; struct ct_request request; unsigned long flags; - unsigned int sleep_period_ms = 1; + unsigned int loop_count = 0; bool send_again; u32 fence; int err; @@ -747,9 +747,11 @@ static int ct_send(struct intel_guc_ct *ct, if (unlikely(ct_deadlocked(ct))) return -EPIPE; - if (msleep_interruptible(sleep_period_ms)) + if (loop_count >= 20) + return -EBUSY; + + if (msleep_interruptible(1 << loop_count++)) return -EINTR; - sleep_period_ms = sleep_period_ms << 1; goto retry; } -- 2.43.0
