1 /* 2 * HND generic pktq operation primitives 3 * 4 * Copyright (C) 1999-2017, Broadcom Corporation 5 * 6 * Unless you and Broadcom execute a separate written software license 7 * agreement governing use of this software, this software is licensed to you 8 * under the terms of the GNU General Public License version 2 (the "GPL"), 9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the 10 * following added to such license: 11 * 12 * As a special exception, the copyright holders of this software give you 13 * permission to link this software with independent modules, and to copy and 14 * distribute the resulting executable under terms of your choice, provided that 15 * you also meet, for each linked independent module, the terms and conditions of 16 * the license of that module. An independent module is a module which is not 17 * derived from this software. The special exception does not apply to any 18 * modifications of the software. 19 * 20 * Notwithstanding the above, under no circumstances may you combine this 21 * software in any way with any other Broadcom software provided under a license 22 * other than the GPL, without Broadcom's express prior written consent. 23 * 24 * 25 * <<Broadcom-WL-IPTag/Open:>> 26 * 27 * $Id: hnd_pktq.h 641285 2016-06-02 02:33:55Z $ 28 */ 29 30 #ifndef _hnd_pktq_h_ 31 #define _hnd_pktq_h_ 32 33 #include <osl_ext.h> 34 35 #ifdef __cplusplus 36 extern "C" { 37 #endif 38 39 /* mutex macros for thread safe */ 40 #ifdef HND_PKTQ_THREAD_SAFE 41 #define HND_PKTQ_MUTEX_DECL(mutex) OSL_EXT_MUTEX_DECL(mutex) 42 #else 43 #define HND_PKTQ_MUTEX_DECL(mutex) 44 #endif 45 46 /* osl multi-precedence packet queue */ 47 #define PKTQ_LEN_MAX 0xFFFF /* Max uint16 65535 packets */ 48 #ifndef PKTQ_LEN_DEFAULT 49 #define PKTQ_LEN_DEFAULT 128 /* Max 128 packets */ 50 #endif 51 #ifndef PKTQ_MAX_PREC 52 #define PKTQ_MAX_PREC 16 /* Maximum precedence levels */ 53 #endif 54 55 typedef struct pktq_prec { 56 void *head; /**< first packet to dequeue */ 57 void *tail; /**< last packet to dequeue */ 58 uint16 len; /**< number of queued packets */ 59 uint16 max; /**< maximum number of queued packets */ 60 } pktq_prec_t; 61 62 #ifdef PKTQ_LOG 63 typedef struct { 64 uint32 requested; /**< packets requested to be stored */ 65 uint32 stored; /**< packets stored */ 66 uint32 saved; /**< packets saved, 67 because a lowest priority queue has given away one packet 68 */ 69 uint32 selfsaved; /**< packets saved, 70 because an older packet from the same queue has been dropped 71 */ 72 uint32 full_dropped; /**< packets dropped, 73 because pktq is full with higher precedence packets 74 */ 75 uint32 dropped; /**< packets dropped because pktq per that precedence is full */ 76 uint32 sacrificed; /**< packets dropped, 77 in order to save one from a queue of a highest priority 78 */ 79 uint32 busy; /**< packets droped because of hardware/transmission error */ 80 uint32 retry; /**< packets re-sent because they were not received */ 81 uint32 ps_retry; /**< packets retried again prior to moving power save mode */ 82 uint32 suppress; /**< packets which were suppressed and not transmitted */ 83 uint32 retry_drop; /**< packets finally dropped after retry limit */ 84 uint32 max_avail; /**< the high-water mark of the queue capacity for packets - 85 goes to zero as queue fills 86 */ 87 uint32 max_used; /**< the high-water mark of the queue utilisation for packets - 88 increases with use ('inverse' of max_avail) 89 */ 90 uint32 queue_capacity; /**< the maximum capacity of the queue */ 91 uint32 rtsfail; /**< count of rts attempts that failed to receive cts */ 92 uint32 acked; /**< count of packets sent (acked) successfully */ 93 uint32 txrate_succ; /**< running total of phy rate of packets sent successfully */ 94 uint32 txrate_main; /**< running totoal of primary phy rate of all packets */ 95 uint32 throughput; /**< actual data transferred successfully */ 96 uint32 airtime; /**< cumulative total medium access delay in useconds */ 97 uint32 _logtime; /**< timestamp of last counter clear */ 98 } pktq_counters_t; 99 100 #define PKTQ_LOG_COMMON \ 101 uint32 pps_time; /**< time spent in ps pretend state */ \ 102 uint32 _prec_log; 103 104 typedef struct { 105 PKTQ_LOG_COMMON 106 pktq_counters_t* _prec_cnt[PKTQ_MAX_PREC]; /**< Counters per queue */ 107 } pktq_log_t; 108 #else 109 typedef struct pktq_log pktq_log_t; 110 #endif /* PKTQ_LOG */ 111 112 113 #define PKTQ_COMMON \ 114 HND_PKTQ_MUTEX_DECL(mutex) \ 115 pktq_log_t *pktqlog; \ 116 uint16 num_prec; /**< number of precedences in use */ \ 117 uint16 hi_prec; /**< rapid dequeue hint (>= highest non-empty prec) */ \ 118 uint16 max; /**< total max packets */ \ 119 uint16 len; /**< total number of packets */ 120 121 /* multi-priority pkt queue */ 122 struct pktq { 123 PKTQ_COMMON 124 /* q array must be last since # of elements can be either PKTQ_MAX_PREC or 1 */ 125 struct pktq_prec q[PKTQ_MAX_PREC]; 126 }; 127 128 /* simple, non-priority pkt queue */ 129 struct spktq { 130 PKTQ_COMMON 131 /* q array must be last since # of elements can be either PKTQ_MAX_PREC or 1 */ 132 struct pktq_prec q[1]; 133 }; 134 135 #define PKTQ_PREC_ITER(pq, prec) for (prec = (pq)->num_prec - 1; prec >= 0; prec--) 136 137 /* fn(pkt, arg). return true if pkt belongs to bsscfg */ 138 typedef bool (*ifpkt_cb_t)(void*, int); 139 140 /* 141 * pktq filter support 142 */ 143 144 /* filter function return values */ 145 typedef enum { 146 PKT_FILTER_NOACTION = 0, /**< restore the pkt to its position in the queue */ 147 PKT_FILTER_DELETE = 1, /**< delete the pkt */ 148 PKT_FILTER_REMOVE = 2, /**< do not restore the pkt to the queue, 149 * filter fn has taken ownership of the pkt 150 */ 151 } pktq_filter_result_t; 152 153 /** 154 * Caller supplied filter function to pktq_pfilter(), pktq_filter(). 155 * Function filter(ctx, pkt) is called with its ctx pointer on each pkt in the 156 * pktq. When the filter function is called, the supplied pkt will have been 157 * unlinked from the pktq. The filter function returns a pktq_filter_result_t 158 * result specifying the action pktq_filter()/pktq_pfilter() should take for 159 * the pkt. 160 * Here are the actions taken by pktq_filter/pfilter() based on the supplied 161 * filter function's return value: 162 * 163 * PKT_FILTER_NOACTION - The filter will re-link the pkt at its 164 * previous location. 165 * 166 * PKT_FILTER_DELETE - The filter will not relink the pkt and will 167 * call the user supplied defer_free_pkt fn on the packet. 168 * 169 * PKT_FILTER_REMOVE - The filter will not relink the pkt. The supplied 170 * filter fn took ownership (or deleted) the pkt. 171 * 172 * WARNING: pkts inserted by the user (in pkt_filter and/or flush callbacks 173 * and chains) in the prec queue will not be seen by the filter, and the prec 174 * queue will be temporarily be removed from the queue hence there're side 175 * effects including pktq_len() on the queue won't reflect the correct number 176 * of packets in the queue. 177 */ 178 typedef pktq_filter_result_t (*pktq_filter_t)(void* ctx, void* pkt); 179 180 /* The defer_free_pkt callback is invoked when the the pktq_filter callback 181 * returns PKT_FILTER_DELETE decision, which allows the user to deposite 182 * the packet appropriately based on the situation (free the packet or 183 * save it in a temporary queue etc.). 184 */ 185 typedef void (*defer_free_pkt_fn_t)(void *ctx, void *pkt); 186 187 /* The flush_free_pkt callback is invoked when all packets in the pktq 188 * are processed. 189 */ 190 typedef void (*flush_free_pkt_fn_t)(void *ctx); 191 192 /* filter a pktq, using the caller supplied filter/deposition/flush functions */ 193 extern void pktq_filter(struct pktq *pq, pktq_filter_t fn, void* arg, 194 defer_free_pkt_fn_t defer, void *defer_ctx, flush_free_pkt_fn_t flush, void *flush_ctx); 195 /* filter a particular precedence in pktq, using the caller supplied filter function */ 196 extern void pktq_pfilter(struct pktq *pq, int prec, pktq_filter_t fn, void* arg, 197 defer_free_pkt_fn_t defer, void *defer_ctx, flush_free_pkt_fn_t flush, void *flush_ctx); 198 199 /* operations on a specific precedence in packet queue */ 200 201 #define pktq_psetmax(pq, prec, _max) ((pq)->q[prec].max = (_max)) 202 #define pktq_pmax(pq, prec) ((pq)->q[prec].max) 203 #define pktq_plen(pq, prec) ((pq)->q[prec].len) 204 #define pktq_pempty(pq, prec) ((pq)->q[prec].len == 0) 205 #define pktq_ppeek(pq, prec) ((pq)->q[prec].head) 206 #define pktq_ppeek_tail(pq, prec) ((pq)->q[prec].tail) 207 #ifdef HND_PKTQ_THREAD_SAFE 208 extern int pktq_pavail(struct pktq *pq, int prec); 209 extern bool pktq_pfull(struct pktq *pq, int prec); 210 #else 211 #define pktq_pavail(pq, prec) ((pq)->q[prec].max - (pq)->q[prec].len) 212 #define pktq_pfull(pq, prec) ((pq)->q[prec].len >= (pq)->q[prec].max) 213 #endif /* HND_PKTQ_THREAD_SAFE */ 214 215 extern void pktq_append(struct pktq *pq, int prec, struct spktq *list); 216 extern void pktq_prepend(struct pktq *pq, int prec, struct spktq *list); 217 218 extern void *pktq_penq(struct pktq *pq, int prec, void *p); 219 extern void *pktq_penq_head(struct pktq *pq, int prec, void *p); 220 extern void *pktq_pdeq(struct pktq *pq, int prec); 221 extern void *pktq_pdeq_prev(struct pktq *pq, int prec, void *prev_p); 222 extern void *pktq_pdeq_with_fn(struct pktq *pq, int prec, ifpkt_cb_t fn, int arg); 223 extern void *pktq_pdeq_tail(struct pktq *pq, int prec); 224 /* Remove a specified packet from its queue */ 225 extern bool pktq_pdel(struct pktq *pq, void *p, int prec); 226 227 /* operations on a set of precedences in packet queue */ 228 229 extern int pktq_mlen(struct pktq *pq, uint prec_bmp); 230 extern void *pktq_mdeq(struct pktq *pq, uint prec_bmp, int *prec_out); 231 extern void *pktq_mpeek(struct pktq *pq, uint prec_bmp, int *prec_out); 232 233 /* operations on packet queue as a whole */ 234 235 #define pktq_len(pq) ((int)(pq)->len) 236 #define pktq_max(pq) ((int)(pq)->max) 237 #define pktq_empty(pq) ((pq)->len == 0) 238 #ifdef HND_PKTQ_THREAD_SAFE 239 extern int pktq_avail(struct pktq *pq); 240 extern bool pktq_full(struct pktq *pq); 241 #else 242 #define pktq_avail(pq) ((int)((pq)->max - (pq)->len)) 243 #define pktq_full(pq) ((pq)->len >= (pq)->max) 244 #endif /* HND_PKTQ_THREAD_SAFE */ 245 246 /* operations for single precedence queues */ 247 #define pktenq(pq, p) pktq_penq(((struct pktq *)(void *)pq), 0, (p)) 248 #define pktenq_head(pq, p) pktq_penq_head(((struct pktq *)(void *)pq), 0, (p)) 249 #define pktdeq(pq) pktq_pdeq(((struct pktq *)(void *)pq), 0) 250 #define pktdeq_tail(pq) pktq_pdeq_tail(((struct pktq *)(void *)pq), 0) 251 #define pktqflush(osh, pq, dir) pktq_pflush(osh, ((struct pktq *)(void *)pq), 0, dir) 252 #define pktqinit(pq, len) pktq_init(((struct pktq *)(void *)pq), 1, len) 253 #define pktqdeinit(pq) pktq_deinit((struct pktq *)(void *)pq) 254 #define pktqavail(pq) pktq_avail((struct pktq *)(void *)pq) 255 #define pktqfull(pq) pktq_full((struct pktq *)(void *)pq) 256 #define pktqfilter(pq, fltr, fltr_ctx, defer, defer_ctx, flush, flush_ctx) \ 257 pktq_pfilter((struct pktq *)pq, 0, fltr, fltr_ctx, defer, defer_ctx, flush, flush_ctx) 258 259 /* wrap macros for modules in components use */ 260 #define spktqinit(pq, max_pkts) pktqinit(pq, max_pkts) 261 #define spktenq(pq, p) pktenq(pq, p) 262 #define spktdeq(pq) pktdeq(pq) 263 264 extern bool pktq_init(struct pktq *pq, int num_prec, int max_len); 265 extern bool pktq_deinit(struct pktq *pq); 266 267 extern void pktq_set_max_plen(struct pktq *pq, int prec, int max_len); 268 269 /* prec_out may be NULL if caller is not interested in return value */ 270 extern void *pktq_deq(struct pktq *pq, int *prec_out); 271 extern void *pktq_deq_tail(struct pktq *pq, int *prec_out); 272 extern void *pktq_peek(struct pktq *pq, int *prec_out); 273 extern void *pktq_peek_tail(struct pktq *pq, int *prec_out); 274 275 /* flush pktq */ 276 extern void pktq_flush(osl_t *osh, struct pktq *pq, bool dir); 277 /* Empty the queue at particular precedence level */ 278 extern void pktq_pflush(osl_t *osh, struct pktq *pq, int prec, bool dir); 279 280 #ifdef __cplusplus 281 } 282 #endif 283 284 #endif /* _hnd_pktq_h_ */ 285