1b2441318SGreg Kroah-Hartman /* SPDX-License-Identifier: GPL-2.0 */ 275957ba3STom Herbert /* 375957ba3STom Herbert * Dynamic queue limits (dql) - Definitions 475957ba3STom Herbert * 575957ba3STom Herbert * Copyright (c) 2011, Tom Herbert <[email protected]> 675957ba3STom Herbert * 775957ba3STom Herbert * This header file contains the definitions for dynamic queue limits (dql). 875957ba3STom Herbert * dql would be used in conjunction with a producer/consumer type queue 975957ba3STom Herbert * (possibly a HW queue). Such a queue would have these general properties: 1075957ba3STom Herbert * 1175957ba3STom Herbert * 1) Objects are queued up to some limit specified as number of objects. 1275957ba3STom Herbert * 2) Periodically a completion process executes which retires consumed 1375957ba3STom Herbert * objects. 1475957ba3STom Herbert * 3) Starvation occurs when limit has been reached, all queued data has 1575957ba3STom Herbert * actually been consumed, but completion processing has not yet run 1675957ba3STom Herbert * so queuing new data is blocked. 1775957ba3STom Herbert * 4) Minimizing the amount of queued data is desirable. 1875957ba3STom Herbert * 1975957ba3STom Herbert * The goal of dql is to calculate the limit as the minimum number of objects 2075957ba3STom Herbert * needed to prevent starvation. 2175957ba3STom Herbert * 2275957ba3STom Herbert * The primary functions of dql are: 2375957ba3STom Herbert * dql_queued - called when objects are enqueued to record number of objects 2475957ba3STom Herbert * dql_avail - returns how many objects are available to be queued based 2575957ba3STom Herbert * on the object limit and how many objects are already enqueued 2675957ba3STom Herbert * dql_completed - called at completion time to indicate how many objects 2775957ba3STom Herbert * were retired from the queue 2875957ba3STom Herbert * 2975957ba3STom Herbert * The dql implementation does not implement any locking for the dql data 3075957ba3STom Herbert * structures, the higher layer should provide this. dql_queued should 3175957ba3STom Herbert * be serialized to prevent concurrent execution of the function; this 3275957ba3STom Herbert * is also true for dql_completed. However, dql_queued and dlq_completed can 3375957ba3STom Herbert * be executed concurrently (i.e. they can be protected by different locks). 3475957ba3STom Herbert */ 3575957ba3STom Herbert 3675957ba3STom Herbert #ifndef _LINUX_DQL_H 3775957ba3STom Herbert #define _LINUX_DQL_H 3875957ba3STom Herbert 3975957ba3STom Herbert #ifdef __KERNEL__ 4075957ba3STom Herbert 416025b913SJakub Kicinski #include <linux/bitops.h> 420cd39f46SPeter Zijlstra #include <asm/bug.h> 430cd39f46SPeter Zijlstra 446025b913SJakub Kicinski #define DQL_HIST_LEN 4 456025b913SJakub Kicinski #define DQL_HIST_ENT(dql, idx) ((dql)->history[(idx) % DQL_HIST_LEN]) 466025b913SJakub Kicinski 4775957ba3STom Herbert struct dql { 4875957ba3STom Herbert /* Fields accessed in enqueue path (dql_queued) */ 4975957ba3STom Herbert unsigned int num_queued; /* Total ever queued */ 5075957ba3STom Herbert unsigned int adj_limit; /* limit + num_completed */ 5175957ba3STom Herbert unsigned int last_obj_cnt; /* Count at last queuing */ 5275957ba3STom Herbert 536025b913SJakub Kicinski unsigned long history_head; /* top 58 bits of jiffies */ 546025b913SJakub Kicinski /* stall entries, a bit per entry */ 556025b913SJakub Kicinski unsigned long history[DQL_HIST_LEN]; 566025b913SJakub Kicinski 5775957ba3STom Herbert /* Fields accessed only by completion path (dql_completed) */ 5875957ba3STom Herbert 5975957ba3STom Herbert unsigned int limit ____cacheline_aligned_in_smp; /* Current limit */ 6075957ba3STom Herbert unsigned int num_completed; /* Total ever completed */ 6175957ba3STom Herbert 6275957ba3STom Herbert unsigned int prev_ovlimit; /* Previous over limit */ 6375957ba3STom Herbert unsigned int prev_num_queued; /* Previous queue total */ 6475957ba3STom Herbert unsigned int prev_last_obj_cnt; /* Previous queuing cnt */ 6575957ba3STom Herbert 6675957ba3STom Herbert unsigned int lowest_slack; /* Lowest slack found */ 6775957ba3STom Herbert unsigned long slack_start_time; /* Time slacks seen */ 6875957ba3STom Herbert 6975957ba3STom Herbert /* Configuration */ 7075957ba3STom Herbert unsigned int max_limit; /* Max limit */ 7175957ba3STom Herbert unsigned int min_limit; /* Minimum limit */ 7275957ba3STom Herbert unsigned int slack_hold_time; /* Time to measure slack */ 736025b913SJakub Kicinski 746025b913SJakub Kicinski /* Stall threshold (in jiffies), defined by user */ 756025b913SJakub Kicinski unsigned short stall_thrs; 766025b913SJakub Kicinski /* Longest stall detected, reported to user */ 776025b913SJakub Kicinski unsigned short stall_max; 786025b913SJakub Kicinski unsigned long last_reap; /* Last reap (in jiffies) */ 796025b913SJakub Kicinski unsigned long stall_cnt; /* Number of stalls */ 8075957ba3STom Herbert }; 8175957ba3STom Herbert 8275957ba3STom Herbert /* Set some static maximums */ 8375957ba3STom Herbert #define DQL_MAX_OBJECT (UINT_MAX / 16) 8475957ba3STom Herbert #define DQL_MAX_LIMIT ((UINT_MAX / 2) - DQL_MAX_OBJECT) 8575957ba3STom Herbert 86*cbe481a1SBreno Leitao /* Populate the bitmap to be processed later in dql_check_stall() */ 87*cbe481a1SBreno Leitao static inline void dql_queue_stall(struct dql *dql) 8875957ba3STom Herbert { 896025b913SJakub Kicinski unsigned long map, now, now_hi, i; 906025b913SJakub Kicinski 916025b913SJakub Kicinski now = jiffies; 926025b913SJakub Kicinski now_hi = now / BITS_PER_LONG; 936025b913SJakub Kicinski 946025b913SJakub Kicinski /* The following code set a bit in the ring buffer, where each 956025b913SJakub Kicinski * bit trackes time the packet was queued. The dql->history buffer 966025b913SJakub Kicinski * tracks DQL_HIST_LEN * BITS_PER_LONG time (jiffies) slot 976025b913SJakub Kicinski */ 986025b913SJakub Kicinski if (unlikely(now_hi != dql->history_head)) { 996025b913SJakub Kicinski /* About to reuse slots, clear them */ 1006025b913SJakub Kicinski for (i = 0; i < DQL_HIST_LEN; i++) { 1016025b913SJakub Kicinski /* Multiplication masks high bits */ 1026025b913SJakub Kicinski if (now_hi * BITS_PER_LONG == 1036025b913SJakub Kicinski (dql->history_head + i) * BITS_PER_LONG) 1046025b913SJakub Kicinski break; 1056025b913SJakub Kicinski DQL_HIST_ENT(dql, dql->history_head + i + 1) = 0; 1066025b913SJakub Kicinski } 1076025b913SJakub Kicinski /* pairs with smp_rmb() in dql_check_stall() */ 1086025b913SJakub Kicinski smp_wmb(); 1096025b913SJakub Kicinski WRITE_ONCE(dql->history_head, now_hi); 1106025b913SJakub Kicinski } 1116025b913SJakub Kicinski 1126025b913SJakub Kicinski /* __set_bit() does not guarantee WRITE_ONCE() semantics */ 1136025b913SJakub Kicinski map = DQL_HIST_ENT(dql, now_hi); 1146025b913SJakub Kicinski 1156025b913SJakub Kicinski /* Populate the history with an entry (bit) per queued */ 1166025b913SJakub Kicinski if (!(map & BIT_MASK(now))) 1176025b913SJakub Kicinski WRITE_ONCE(DQL_HIST_ENT(dql, now_hi), map | BIT_MASK(now)); 11875957ba3STom Herbert } 11975957ba3STom Herbert 120*cbe481a1SBreno Leitao /* 121*cbe481a1SBreno Leitao * Record number of objects queued. Assumes that caller has already checked 122*cbe481a1SBreno Leitao * availability in the queue with dql_avail. 123*cbe481a1SBreno Leitao */ 124*cbe481a1SBreno Leitao static inline void dql_queued(struct dql *dql, unsigned int count) 125*cbe481a1SBreno Leitao { 126*cbe481a1SBreno Leitao if (WARN_ON_ONCE(count > DQL_MAX_OBJECT)) 127*cbe481a1SBreno Leitao return; 128*cbe481a1SBreno Leitao 129*cbe481a1SBreno Leitao dql->last_obj_cnt = count; 130*cbe481a1SBreno Leitao 131*cbe481a1SBreno Leitao /* We want to force a write first, so that cpu do not attempt 132*cbe481a1SBreno Leitao * to get cache line containing last_obj_cnt, num_queued, adj_limit 133*cbe481a1SBreno Leitao * in Shared state, but directly does a Request For Ownership 134*cbe481a1SBreno Leitao * It is only a hint, we use barrier() only. 135*cbe481a1SBreno Leitao */ 136*cbe481a1SBreno Leitao barrier(); 137*cbe481a1SBreno Leitao 138*cbe481a1SBreno Leitao dql->num_queued += count; 139*cbe481a1SBreno Leitao 140*cbe481a1SBreno Leitao dql_queue_stall(dql); 141*cbe481a1SBreno Leitao } 142*cbe481a1SBreno Leitao 14375957ba3STom Herbert /* Returns how many objects can be queued, < 0 indicates over limit. */ 14475957ba3STom Herbert static inline int dql_avail(const struct dql *dql) 14575957ba3STom Herbert { 1466aa7de05SMark Rutland return READ_ONCE(dql->adj_limit) - READ_ONCE(dql->num_queued); 14775957ba3STom Herbert } 14875957ba3STom Herbert 14975957ba3STom Herbert /* Record number of completed objects and recalculate the limit. */ 15075957ba3STom Herbert void dql_completed(struct dql *dql, unsigned int count); 15175957ba3STom Herbert 15275957ba3STom Herbert /* Reset dql state */ 15375957ba3STom Herbert void dql_reset(struct dql *dql); 15475957ba3STom Herbert 15575957ba3STom Herbert /* Initialize dql state */ 1567a0947e7SStephen Hemminger void dql_init(struct dql *dql, unsigned int hold_time); 15775957ba3STom Herbert 15875957ba3STom Herbert #endif /* _KERNEL_ */ 15975957ba3STom Herbert 16075957ba3STom Herbert #endif /* _LINUX_DQL_H */ 161