1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
275957ba3STom Herbert /*
375957ba3STom Herbert * Dynamic byte queue limits. See include/linux/dynamic_queue_limits.h
475957ba3STom Herbert *
575957ba3STom Herbert * Copyright (c) 2011, Tom Herbert <[email protected]>
675957ba3STom Herbert */
775957ba3STom Herbert #include <linux/types.h>
875957ba3STom Herbert #include <linux/kernel.h>
9930c514fSTom Herbert #include <linux/jiffies.h>
1075957ba3STom Herbert #include <linux/dynamic_queue_limits.h>
11565ac23bSRasmus Villemoes #include <linux/compiler.h>
12565ac23bSRasmus Villemoes #include <linux/export.h>
136025b913SJakub Kicinski #include <trace/events/napi.h>
1475957ba3STom Herbert
150cfd32b7SHiroaki SHIMODA #define POSDIFF(A, B) ((int)((A) - (B)) > 0 ? (A) - (B) : 0)
1625426b79SHiroaki SHIMODA #define AFTER_EQ(A, B) ((int)((A) - (B)) >= 0)
1775957ba3STom Herbert
dql_check_stall(struct dql * dql,unsigned short stall_thrs)184ba67ef3SBreno Leitao static void dql_check_stall(struct dql *dql, unsigned short stall_thrs)
196025b913SJakub Kicinski {
206025b913SJakub Kicinski unsigned long now;
216025b913SJakub Kicinski
226025b913SJakub Kicinski if (!stall_thrs)
236025b913SJakub Kicinski return;
246025b913SJakub Kicinski
256025b913SJakub Kicinski now = jiffies;
266025b913SJakub Kicinski /* Check for a potential stall */
276025b913SJakub Kicinski if (time_after_eq(now, dql->last_reap + stall_thrs)) {
286025b913SJakub Kicinski unsigned long hist_head, t, start, end;
296025b913SJakub Kicinski
306025b913SJakub Kicinski /* We are trying to detect a period of at least @stall_thrs
316025b913SJakub Kicinski * jiffies without any Tx completions, but during first half
326025b913SJakub Kicinski * of which some Tx was posted.
336025b913SJakub Kicinski */
346025b913SJakub Kicinski dqs_again:
356025b913SJakub Kicinski hist_head = READ_ONCE(dql->history_head);
366025b913SJakub Kicinski /* pairs with smp_wmb() in dql_queued() */
376025b913SJakub Kicinski smp_rmb();
386025b913SJakub Kicinski
396025b913SJakub Kicinski /* Get the previous entry in the ring buffer, which is the
406025b913SJakub Kicinski * oldest sample.
416025b913SJakub Kicinski */
426025b913SJakub Kicinski start = (hist_head - DQL_HIST_LEN + 1) * BITS_PER_LONG;
436025b913SJakub Kicinski
446025b913SJakub Kicinski /* Advance start to continue from the last reap time */
456025b913SJakub Kicinski if (time_before(start, dql->last_reap + 1))
466025b913SJakub Kicinski start = dql->last_reap + 1;
476025b913SJakub Kicinski
486025b913SJakub Kicinski /* Newest sample we should have already seen a completion for */
496025b913SJakub Kicinski end = hist_head * BITS_PER_LONG + (BITS_PER_LONG - 1);
506025b913SJakub Kicinski
516025b913SJakub Kicinski /* Shrink the search space to [start, (now - start_thrs/2)] if
526025b913SJakub Kicinski * `end` is beyond the stall zone
536025b913SJakub Kicinski */
546025b913SJakub Kicinski if (time_before(now, end + stall_thrs / 2))
556025b913SJakub Kicinski end = now - stall_thrs / 2;
566025b913SJakub Kicinski
576025b913SJakub Kicinski /* Search for the queued time in [t, end] */
586025b913SJakub Kicinski for (t = start; time_before_eq(t, end); t++)
596025b913SJakub Kicinski if (test_bit(t % (DQL_HIST_LEN * BITS_PER_LONG),
606025b913SJakub Kicinski dql->history))
616025b913SJakub Kicinski break;
626025b913SJakub Kicinski
636025b913SJakub Kicinski /* Variable t contains the time of the queue */
646025b913SJakub Kicinski if (!time_before_eq(t, end))
656025b913SJakub Kicinski goto no_stall;
666025b913SJakub Kicinski
676025b913SJakub Kicinski /* The ring buffer was modified in the meantime, retry */
686025b913SJakub Kicinski if (hist_head != READ_ONCE(dql->history_head))
696025b913SJakub Kicinski goto dqs_again;
706025b913SJakub Kicinski
716025b913SJakub Kicinski dql->stall_cnt++;
726025b913SJakub Kicinski dql->stall_max = max_t(unsigned short, dql->stall_max, now - t);
736025b913SJakub Kicinski
746025b913SJakub Kicinski trace_dql_stall_detected(dql->stall_thrs, now - t,
756025b913SJakub Kicinski dql->last_reap, dql->history_head,
766025b913SJakub Kicinski now, dql->history);
776025b913SJakub Kicinski }
786025b913SJakub Kicinski no_stall:
796025b913SJakub Kicinski dql->last_reap = now;
806025b913SJakub Kicinski }
816025b913SJakub Kicinski
8275957ba3STom Herbert /* Records completed count and recalculates the queue limit */
dql_completed(struct dql * dql,unsigned int count)8375957ba3STom Herbert void dql_completed(struct dql *dql, unsigned int count)
8475957ba3STom Herbert {
8575957ba3STom Herbert unsigned int inprogress, prev_inprogress, limit;
86914bec10SHiroaki SHIMODA unsigned int ovlimit, completed, num_queued;
874ba67ef3SBreno Leitao unsigned short stall_thrs;
8825426b79SHiroaki SHIMODA bool all_prev_completed;
8975957ba3STom Herbert
906aa7de05SMark Rutland num_queued = READ_ONCE(dql->num_queued);
914ba67ef3SBreno Leitao /* Read stall_thrs in advance since it belongs to the same (first)
924ba67ef3SBreno Leitao * cache line as ->num_queued. This way, dql_check_stall() does not
934ba67ef3SBreno Leitao * need to touch the first cache line again later, reducing the window
944ba67ef3SBreno Leitao * of possible false sharing.
954ba67ef3SBreno Leitao */
964ba67ef3SBreno Leitao stall_thrs = READ_ONCE(dql->stall_thrs);
97914bec10SHiroaki SHIMODA
9875957ba3STom Herbert /* Can't complete more than what's in queue */
99914bec10SHiroaki SHIMODA BUG_ON(count > num_queued - dql->num_completed);
10075957ba3STom Herbert
10175957ba3STom Herbert completed = dql->num_completed + count;
10275957ba3STom Herbert limit = dql->limit;
103914bec10SHiroaki SHIMODA ovlimit = POSDIFF(num_queued - dql->num_completed, limit);
104914bec10SHiroaki SHIMODA inprogress = num_queued - completed;
10575957ba3STom Herbert prev_inprogress = dql->prev_num_queued - dql->num_completed;
10625426b79SHiroaki SHIMODA all_prev_completed = AFTER_EQ(completed, dql->prev_num_queued);
10775957ba3STom Herbert
10875957ba3STom Herbert if ((ovlimit && !inprogress) ||
10975957ba3STom Herbert (dql->prev_ovlimit && all_prev_completed)) {
11075957ba3STom Herbert /*
11175957ba3STom Herbert * Queue considered starved if:
11275957ba3STom Herbert * - The queue was over-limit in the last interval,
11375957ba3STom Herbert * and there is no more data in the queue.
11475957ba3STom Herbert * OR
11575957ba3STom Herbert * - The queue was over-limit in the previous interval and
11675957ba3STom Herbert * when enqueuing it was possible that all queued data
11775957ba3STom Herbert * had been consumed. This covers the case when queue
11875957ba3STom Herbert * may have becomes starved between completion processing
11975957ba3STom Herbert * running and next time enqueue was scheduled.
12075957ba3STom Herbert *
12175957ba3STom Herbert * When queue is starved increase the limit by the amount
12275957ba3STom Herbert * of bytes both sent and completed in the last interval,
12375957ba3STom Herbert * plus any previous over-limit.
12475957ba3STom Herbert */
12575957ba3STom Herbert limit += POSDIFF(completed, dql->prev_num_queued) +
12675957ba3STom Herbert dql->prev_ovlimit;
12775957ba3STom Herbert dql->slack_start_time = jiffies;
12875957ba3STom Herbert dql->lowest_slack = UINT_MAX;
12975957ba3STom Herbert } else if (inprogress && prev_inprogress && !all_prev_completed) {
13075957ba3STom Herbert /*
13175957ba3STom Herbert * Queue was not starved, check if the limit can be decreased.
13275957ba3STom Herbert * A decrease is only considered if the queue has been busy in
13375957ba3STom Herbert * the whole interval (the check above).
13475957ba3STom Herbert *
135dde57fe0SRandy Dunlap * If there is slack, the amount of excess data queued above
136dde57fe0SRandy Dunlap * the amount needed to prevent starvation, the queue limit
13775957ba3STom Herbert * can be decreased. To avoid hysteresis we consider the
13875957ba3STom Herbert * minimum amount of slack found over several iterations of the
13975957ba3STom Herbert * completion routine.
14075957ba3STom Herbert */
14175957ba3STom Herbert unsigned int slack, slack_last_objs;
14275957ba3STom Herbert
14375957ba3STom Herbert /*
14475957ba3STom Herbert * Slack is the maximum of
14575957ba3STom Herbert * - The queue limit plus previous over-limit minus twice
14675957ba3STom Herbert * the number of objects completed. Note that two times
14775957ba3STom Herbert * number of completed bytes is a basis for an upper bound
14875957ba3STom Herbert * of the limit.
14975957ba3STom Herbert * - Portion of objects in the last queuing operation that
15075957ba3STom Herbert * was not part of non-zero previous over-limit. That is
15175957ba3STom Herbert * "round down" by non-overlimit portion of the last
15275957ba3STom Herbert * queueing operation.
15375957ba3STom Herbert */
15475957ba3STom Herbert slack = POSDIFF(limit + dql->prev_ovlimit,
15575957ba3STom Herbert 2 * (completed - dql->num_completed));
15675957ba3STom Herbert slack_last_objs = dql->prev_ovlimit ?
15775957ba3STom Herbert POSDIFF(dql->prev_last_obj_cnt, dql->prev_ovlimit) : 0;
15875957ba3STom Herbert
15975957ba3STom Herbert slack = max(slack, slack_last_objs);
16075957ba3STom Herbert
16175957ba3STom Herbert if (slack < dql->lowest_slack)
16275957ba3STom Herbert dql->lowest_slack = slack;
16375957ba3STom Herbert
16475957ba3STom Herbert if (time_after(jiffies,
16575957ba3STom Herbert dql->slack_start_time + dql->slack_hold_time)) {
16675957ba3STom Herbert limit = POSDIFF(limit, dql->lowest_slack);
16775957ba3STom Herbert dql->slack_start_time = jiffies;
16875957ba3STom Herbert dql->lowest_slack = UINT_MAX;
16975957ba3STom Herbert }
17075957ba3STom Herbert }
17175957ba3STom Herbert
17275957ba3STom Herbert /* Enforce bounds on limit */
17375957ba3STom Herbert limit = clamp(limit, dql->min_limit, dql->max_limit);
17475957ba3STom Herbert
17575957ba3STom Herbert if (limit != dql->limit) {
17675957ba3STom Herbert dql->limit = limit;
17775957ba3STom Herbert ovlimit = 0;
17875957ba3STom Herbert }
17975957ba3STom Herbert
18075957ba3STom Herbert dql->adj_limit = limit + completed;
18175957ba3STom Herbert dql->prev_ovlimit = ovlimit;
182a911bad0SEric Dumazet dql->prev_last_obj_cnt = READ_ONCE(dql->last_obj_cnt);
18375957ba3STom Herbert dql->num_completed = completed;
184914bec10SHiroaki SHIMODA dql->prev_num_queued = num_queued;
1856025b913SJakub Kicinski
1864ba67ef3SBreno Leitao dql_check_stall(dql, stall_thrs);
18775957ba3STom Herbert }
18875957ba3STom Herbert EXPORT_SYMBOL(dql_completed);
18975957ba3STom Herbert
dql_reset(struct dql * dql)19075957ba3STom Herbert void dql_reset(struct dql *dql)
19175957ba3STom Herbert {
19275957ba3STom Herbert /* Reset all dynamic values */
193*3a17f23fSJing Su dql->limit = dql->min_limit;
19475957ba3STom Herbert dql->num_queued = 0;
19575957ba3STom Herbert dql->num_completed = 0;
19675957ba3STom Herbert dql->last_obj_cnt = 0;
19775957ba3STom Herbert dql->prev_num_queued = 0;
19875957ba3STom Herbert dql->prev_last_obj_cnt = 0;
19975957ba3STom Herbert dql->prev_ovlimit = 0;
20075957ba3STom Herbert dql->lowest_slack = UINT_MAX;
20175957ba3STom Herbert dql->slack_start_time = jiffies;
2026025b913SJakub Kicinski
2036025b913SJakub Kicinski dql->last_reap = jiffies;
2046025b913SJakub Kicinski dql->history_head = jiffies / BITS_PER_LONG;
2056025b913SJakub Kicinski memset(dql->history, 0, sizeof(dql->history));
20675957ba3STom Herbert }
20775957ba3STom Herbert EXPORT_SYMBOL(dql_reset);
20875957ba3STom Herbert
dql_init(struct dql * dql,unsigned int hold_time)2097a0947e7SStephen Hemminger void dql_init(struct dql *dql, unsigned int hold_time)
21075957ba3STom Herbert {
21175957ba3STom Herbert dql->max_limit = DQL_MAX_LIMIT;
21275957ba3STom Herbert dql->min_limit = 0;
21375957ba3STom Herbert dql->slack_hold_time = hold_time;
2146025b913SJakub Kicinski dql->stall_thrs = 0;
21575957ba3STom Herbert dql_reset(dql);
21675957ba3STom Herbert }
21775957ba3STom Herbert EXPORT_SYMBOL(dql_init);
218