summaryrefslogtreecommitdiffstats
path: root/kernel/gsp_sema_service.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/gsp_sema_service.c')
-rw-r--r--kernel/gsp_sema_service.c24
1 files changed, 22 insertions, 2 deletions
diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c
index 25ae31f..d47ec08 100644
--- a/kernel/gsp_sema_service.c
+++ b/kernel/gsp_sema_service.c
@@ -25108,8 +25108,28 @@ static void svc_stall_watch_check(void)
svc_stall_watch_last = jiffies; /* re-arm the window */
if (svc_stall_watch_dumps >= SVC_STALL_WATCH_DUMPS)
return;
- if (!svc_pending_n && !svc.opdef_held)
- return; /* idle boot, not a stall */
+ /*
+ * r563c: gate on ACTIVE withheld work, not on the cumulative counters.
+ * r566 evidence: the dump fired four times with done=8929 and
+ * opdef=215/7/5 frozen - but the ring was EMPTY (every channel
+ * last_get == put: the clients were simply waiting and no entry was
+ * pending), and the forced flush had nothing to deliver. `opdef_held`
+ * is a lifetime counter (215 holds applied/expired long ago), not
+ * proof of a current hold. A real stall has either a pending
+ * translation (svc_pending_n) or an ACTIVE opdef slot with releases
+ * recorded (e->active && e->n) - only then is there something the
+ * pump is withholding.
+ */
+ {
+ bool work = svc_pending_n != 0;
+ u32 wi;
+
+ for (wi = 0; wi < SVC_OPDEF_SLOTS && !work; wi++)
+ if (svc_opdef[wi].active && svc_opdef[wi].n)
+ work = true;
+ if (!work)
+ return;
+ }
svc_stall_watch_dumps++;
svc_stall_watch_dump();
/*