summaryrefslogtreecommitdiff
path: root/include/net/codel_impl.h
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2026-09-22 18:32:50 +1000
committerDave Airlie <airlied@redhat.com>2026-09-22 18:35:06 +1000
commitb0a3a811634aa7422f8a92196db47a06a70bda16 (patch)
tree15f8b05b9a0e99e87fecb6751a0a9ef59589c28c /include/net/codel_impl.h
parent014ee7742bed896f1aee13ecdee5fe8c7826c0a1 (diff)
parent93f51579e7df248780214094418f205253383cc5 (diff)
Backmerge tag 'v7.3-rc4' into drm-next
Linux 7.3-rc4 Requested by Philipp Stanner for 2ab510e63197360945f915dd5631a77c63ac6b27 would be needed as a groundlayer for further patches that extend the locking in drm_sched Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'include/net/codel_impl.h')
-rw-r--r--include/net/codel_impl.h16
1 files changed, 15 insertions, 1 deletions
diff --git a/include/net/codel_impl.h b/include/net/codel_impl.h
index 2c1f0ec309e9..8f26132d45b7 100644
--- a/include/net/codel_impl.h
+++ b/include/net/codel_impl.h
@@ -93,12 +93,17 @@ static void codel_Newton_step(struct codel_vars *vars)
* CoDel control_law is t + interval/sqrt(count)
* We maintain in rec_inv_sqrt the reciprocal value of sqrt(count) to avoid
* both sqrt() and divide operation.
+ *
+ * Clamp the increment to at least 1 tick: a very small interval (or a
+ * large count) can truncate it to zero, stalling the dropping loop.
*/
static codel_time_t codel_control_law(codel_time_t t,
codel_time_t interval,
u32 rec_inv_sqrt)
{
- return t + reciprocal_scale(interval, rec_inv_sqrt << REC_INV_SQRT_SHIFT);
+ return t + max_t(u32, 1,
+ reciprocal_scale(interval,
+ rec_inv_sqrt << REC_INV_SQRT_SHIFT));
}
static bool codel_should_drop(const struct sk_buff *skb,
@@ -154,6 +159,7 @@ static struct sk_buff *codel_dequeue(void *ctx,
codel_skb_dequeue_t dequeue_func)
{
struct sk_buff *skb = dequeue_func(vars, ctx);
+ unsigned int drops = 0;
codel_time_t now;
bool drop;
@@ -180,6 +186,14 @@ static struct sk_buff *codel_dequeue(void *ctx,
*/
while (vars->dropping &&
codel_time_after_eq(now, vars->drop_next)) {
+ if (++drops > CODEL_MAX_DROPS_PER_DEQUEUE) {
+ /* fell far behind the schedule */
+ WRITE_ONCE(vars->drop_next,
+ codel_control_law(now,
+ params->interval,
+ vars->rec_inv_sqrt));
+ break;
+ }
/* dont care of possible wrap
* since there is no more divide.
*/