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 18*4ba67ef3SBreno 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 */ 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; 87*4ba67ef3SBreno Leitao unsigned short stall_thrs; 8825426b79SHiroaki SHIMODA bool all_prev_completed; 8975957ba3STom Herbert 906aa7de05SMark Rutland num_queued = READ_ONCE(dql->num_queued); 91*4ba67ef3SBreno Leitao /* Read stall_thrs in advance since it belongs to the same (first) 92*4ba67ef3SBreno Leitao * cache line as ->num_queued. This way, dql_check_stall() does not 93*4ba67ef3SBreno Leitao * need to touch the first cache line again later, reducing the window 94*4ba67ef3SBreno Leitao * of possible false sharing. 95*4ba67ef3SBreno Leitao */ 96*4ba67ef3SBreno 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; 18275957ba3STom Herbert dql->prev_last_obj_cnt = dql->last_obj_cnt; 18375957ba3STom Herbert dql->num_completed = completed; 184914bec10SHiroaki SHIMODA dql->prev_num_queued = num_queued; 1856025b913SJakub Kicinski 186*4ba67ef3SBreno Leitao dql_check_stall(dql, stall_thrs); 18775957ba3STom Herbert } 18875957ba3STom Herbert EXPORT_SYMBOL(dql_completed); 18975957ba3STom Herbert 19075957ba3STom Herbert void dql_reset(struct dql *dql) 19175957ba3STom Herbert { 19275957ba3STom Herbert /* Reset all dynamic values */ 19375957ba3STom Herbert dql->limit = 0; 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 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