1 /* 2 * HND generic pktq operation primitives 3 * 4 * Copyright (C) 1999-2019, Broadcom. 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 16 * of the license of that module. An independent module is a module which is 17 * not 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 698847 2017-05-11 00:10:48Z $ 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 // 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 // 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 // endif 51 #ifndef PKTQ_MAX_PREC 52 #define PKTQ_MAX_PREC 16 /* Maximum precedence levels */ 53 #endif // endif 54 55 /** Queue for a single precedence level */ 56 typedef struct pktq_prec { 57 void *head; /**< first packet to dequeue */ 58 void *tail; /**< last packet to dequeue */ 59 uint16 n_pkts; /**< number of queued packets */ 60 uint16 max_pkts; /**< maximum number of queued packets */ 61 uint16 stall_count; /**< # seconds since no packets are dequeued */ 62 uint16 dequeue_count; /**< # of packets dequeued in last 1 second */ 63 } pktq_prec_t; 64 65 #ifdef PKTQ_LOG 66 typedef struct { 67 uint32 requested; /**< packets requested to be stored */ 68 uint32 stored; /**< packets stored */ 69 uint32 70 saved; /**< packets saved, 71 because a lowest priority queue has given away one packet 72 */ 73 uint32 selfsaved; /**< packets saved, 74 because an older packet from the same queue has 75 been dropped 76 */ 77 uint32 78 full_dropped; /**< packets dropped, 79 because pktq is full with higher precedence packets 80 */ 81 uint32 dropped; /**< packets dropped because pktq per that precedence is 82 full */ 83 uint32 sacrificed; /**< packets dropped, 84 in order to save one from a queue of a highest 85 priority 86 */ 87 uint32 busy; /**< packets droped because of hardware/transmission error */ 88 uint32 retry; /**< packets re-sent because they were not received */ 89 uint32 90 ps_retry; /**< packets retried again prior to moving power save mode */ 91 uint32 suppress; /**< packets which were suppressed and not transmitted */ 92 uint32 retry_drop; /**< packets finally dropped after retry limit */ 93 uint32 max_avail; /**< the high-water mark of the queue capacity for packets 94 - goes to zero as queue fills 95 */ 96 uint32 max_used; /**< the high-water mark of the queue utilisation for 97 packets - increases with use ('inverse' of max_avail) 98 */ 99 uint32 queue_capacity; /**< the maximum capacity of the queue */ 100 uint32 rtsfail; /**< count of rts attempts that failed to receive cts */ 101 uint32 acked; /**< count of packets sent (acked) successfully */ 102 uint32 txrate_succ; /**< running total of phy rate of packets sent 103 successfully */ 104 uint32 105 txrate_main; /**< running totoal of primary phy rate of all packets */ 106 uint32 throughput; /**< actual data transferred successfully */ 107 uint32 airtime; /**< cumulative total medium access delay in useconds */ 108 uint32 _logtime; /**< timestamp of last counter clear */ 109 } pktq_counters_t; 110 111 #define PKTQ_LOG_COMMON \ 112 uint32 pps_time; /**< time spent in ps pretend state */ \ 113 uint32 _prec_log; 114 115 typedef struct { 116 PKTQ_LOG_COMMON 117 pktq_counters_t *_prec_cnt[PKTQ_MAX_PREC]; /**< Counters per queue */ 118 } pktq_log_t; 119 #else 120 typedef struct pktq_log pktq_log_t; 121 #endif /* PKTQ_LOG */ 122 123 #define PKTQ_COMMON \ 124 HND_PKTQ_MUTEX_DECL(mutex) \ 125 pktq_log_t *pktqlog; \ 126 uint16 num_prec; /**< number of precedences in use */ \ 127 uint16 hi_prec; /**< rapid dequeue hint (>= highest non-empty prec) */ \ 128 uint16 max_pkts; /**< max packets */ \ 129 uint16 n_pkts_tot; /**< total (cummulative over all precedences) number of \ 130 packets */ 131 132 /** multi-priority packet queue */ 133 struct pktq { 134 PKTQ_COMMON 135 /* q array must be last since # of elements can be either PKTQ_MAX_PREC or 1 136 */ 137 struct pktq_prec q[PKTQ_MAX_PREC]; 138 }; 139 140 /** simple, non-priority packet queue */ 141 struct spktq { 142 HND_PKTQ_MUTEX_DECL(mutex) 143 struct pktq_prec q; 144 }; 145 146 #define PKTQ_PREC_ITER(pq, prec) \ 147 for (prec = (pq)->num_prec - 1; prec >= 0; prec--) 148 149 /* fn(pkt, arg). return true if pkt belongs to bsscfg */ 150 typedef bool (*ifpkt_cb_t)(void *, int); 151 152 /* 153 * pktq filter support 154 */ 155 156 /** filter function return values */ 157 typedef enum { 158 PKT_FILTER_NOACTION = 159 0, /**< restore the pkt to its position in the queue */ 160 PKT_FILTER_DELETE = 1, /**< delete the pkt */ 161 PKT_FILTER_REMOVE = 2, /**< do not restore the pkt to the queue, 162 * filter fn has taken ownership of the pkt 163 */ 164 } pktq_filter_result_t; 165 166 /** 167 * Caller supplied filter function to pktq_pfilter(), pktq_filter(). 168 * Function filter(ctx, pkt) is called with its ctx pointer on each pkt in the 169 * pktq. When the filter function is called, the supplied pkt will have been 170 * unlinked from the pktq. The filter function returns a pktq_filter_result_t 171 * result specifying the action pktq_filter()/pktq_pfilter() should take for 172 * the pkt. 173 * Here are the actions taken by pktq_filter/pfilter() based on the supplied 174 * filter function's return value 175 * 176 * PKT_FILTER_NOACTION - The filter will re-link the pkt at its 177 * previous location. 178 * 179 * PKT_FILTER_DELETE - The filter will not relink the pkt and will 180 * call the user supplied defer_free_pkt fn on the packet. 181 * 182 * PKT_FILTER_REMOVE - The filter will not relink the pkt. The supplied 183 * filter fn took ownership (or deleted) the pkt. 184 * 185 * WARNING: pkts inserted by the user (in pkt_filter and/or flush callbacks 186 * and chains) in the prec queue will not be seen by the filter, and the prec 187 * queue will be temporarily be removed from the queue hence there're side 188 * effects including pktq_n_pkts_tot() on the queue won't reflect the correct 189 * number of packets in the queue. 190 */ 191 192 typedef pktq_filter_result_t (*pktq_filter_t)(void *ctx, void *pkt); 193 194 /** 195 * The defer_free_pkt callback is invoked when the the pktq_filter callback 196 * returns PKT_FILTER_DELETE decision, which allows the user to deposite 197 * the packet appropriately based on the situation (free the packet or 198 * save it in a temporary queue etc.). 199 */ 200 typedef void (*defer_free_pkt_fn_t)(void *ctx, void *pkt); 201 202 /** 203 * The flush_free_pkt callback is invoked when all packets in the pktq 204 * are processed. 205 */ 206 typedef void (*flush_free_pkt_fn_t)(void *ctx); 207 208 #if defined(WLAMPDU_MAC) && defined(PROP_TXSTATUS) 209 /* this callback will be invoked when in low_txq_scb flush() 210 * two back-to-back pkts has same epoch value. 211 */ 212 typedef void (*flip_epoch_t)(void *ctx, void *pkt, uint8 *flipEpoch, 213 uint8 *lastEpoch); 214 #endif /* defined(WLAMPDU_MAC) && defined(PROP_TXSTATUS) */ 215 216 /** filter a pktq, using the caller supplied filter/deposition/flush functions 217 */ 218 extern void pktq_filter(struct pktq *pq, pktq_filter_t fn, void *arg, 219 defer_free_pkt_fn_t defer, void *defer_ctx, 220 flush_free_pkt_fn_t flush, void *flush_ctx); 221 /** filter a particular precedence in pktq, using the caller supplied filter 222 * function */ 223 extern void pktq_pfilter(struct pktq *pq, int prec, pktq_filter_t fn, void *arg, 224 defer_free_pkt_fn_t defer, void *defer_ctx, 225 flush_free_pkt_fn_t flush, void *flush_ctx); 226 /** filter a simple non-precedence in spktq, using the caller supplied filter 227 * function */ 228 extern void spktq_filter(struct spktq *spq, pktq_filter_t fltr, void *fltr_ctx, 229 defer_free_pkt_fn_t defer, void *defer_ctx, 230 flush_free_pkt_fn_t flush, void *flush_ctx); 231 232 /* operations on a specific precedence in packet queue */ 233 #define pktqprec_max_pkts(pq, prec) ((pq)->q[prec].max_pkts) 234 #define pktqprec_n_pkts(pq, prec) ((pq)->q[prec].n_pkts) 235 #define pktqprec_empty(pq, prec) ((pq)->q[prec].n_pkts == 0) 236 #define pktqprec_peek(pq, prec) ((pq)->q[prec].head) 237 #define pktqprec_peek_tail(pq, prec) ((pq)->q[prec].tail) 238 #define spktq_peek_tail(pq) ((pq)->q.tail) 239 #ifdef HND_PKTQ_THREAD_SAFE 240 extern int pktqprec_avail_pkts(struct pktq *pq, int prec); 241 extern bool pktqprec_full(struct pktq *pq, int prec); 242 #else 243 #define pktqprec_avail_pkts(pq, prec) \ 244 ((pq)->q[prec].max_pkts - (pq)->q[prec].n_pkts) 245 #define pktqprec_full(pq, prec) ((pq)->q[prec].n_pkts >= (pq)->q[prec].max_pkts) 246 #endif /* HND_PKTQ_THREAD_SAFE */ 247 248 extern void pktq_append(struct pktq *pq, int prec, struct spktq *list); 249 extern void spktq_append(struct spktq *spq, struct spktq *list); 250 extern void pktq_prepend(struct pktq *pq, int prec, struct spktq *list); 251 extern void spktq_prepend(struct spktq *spq, struct spktq *list); 252 extern void *pktq_penq(struct pktq *pq, int prec, void *p); 253 extern void *pktq_penq_head(struct pktq *pq, int prec, void *p); 254 extern void *pktq_pdeq(struct pktq *pq, int prec); 255 extern void *pktq_pdeq_prev(struct pktq *pq, int prec, void *prev_p); 256 extern void *pktq_pdeq_with_fn(struct pktq *pq, int prec, ifpkt_cb_t fn, 257 int arg); 258 extern void *pktq_pdeq_tail(struct pktq *pq, int prec); 259 /** Remove a specified packet from its queue */ 260 extern bool pktq_pdel(struct pktq *pq, void *p, int prec); 261 262 /* For single precedence queues */ 263 extern void *spktq_enq(struct spktq *spq, void *p); 264 extern void *spktq_enq_head(struct spktq *spq, void *p); 265 extern void *spktq_deq(struct spktq *spq); 266 extern void *spktq_deq_tail(struct spktq *spq); 267 268 /* operations on a set of precedences in packet queue */ 269 270 extern int pktq_mlen(struct pktq *pq, uint prec_bmp); 271 extern void *pktq_mdeq(struct pktq *pq, uint prec_bmp, int *prec_out); 272 extern void *pktq_mpeek(struct pktq *pq, uint prec_bmp, int *prec_out); 273 274 /* operations on packet queue as a whole */ 275 276 #define pktq_n_pkts_tot(pq) ((int)(pq)->n_pkts_tot) 277 #define pktq_max(pq) ((int)(pq)->max_pkts) 278 #define pktq_empty(pq) ((pq)->n_pkts_tot == 0) 279 #define spktq_n_pkts(spq) ((int)(spq)->q.n_pkts) 280 #define spktq_empty(spq) ((spq)->q.n_pkts == 0) 281 282 #define spktq_max(spq) ((int)(spq)->q.max_pkts) 283 #define spktq_empty(spq) ((spq)->q.n_pkts == 0) 284 #ifdef HND_PKTQ_THREAD_SAFE 285 extern int pktq_avail(struct pktq *pq); 286 extern bool pktq_full(struct pktq *pq); 287 extern int spktq_avail(struct spktq *spq); 288 extern bool spktq_full(struct spktq *spq); 289 #else 290 #define pktq_avail(pq) ((int)((pq)->max_pkts - (pq)->n_pkts_tot)) 291 #define pktq_full(pq) ((pq)->n_pkts_tot >= (pq)->max_pkts) 292 #define spktq_avail(spq) ((int)((spq)->q.max_pkts - (spq)->q.n_pkts)) 293 #define spktq_full(spq) ((spq)->q.n_pkts >= (spq)->q.max_pkts) 294 #endif /* HND_PKTQ_THREAD_SAFE */ 295 296 /* operations for single precedence queues */ 297 #define pktenq(pq, p) pktq_penq((pq), 0, (p)) 298 #define pktenq_head(pq, p) pktq_penq_head((pq), 0, (p)) 299 #define pktdeq(pq) pktq_pdeq((pq), 0) 300 #define pktdeq_tail(pq) pktq_pdeq_tail((pq), 0) 301 #define pktqflush(osh, pq, dir) pktq_pflush(osh, (pq), 0, (dir)) 302 #define pktqinit(pq, max_pkts) pktq_init((pq), 1, (max_pkts)) 303 #define pktqdeinit(pq) pktq_deinit((pq)) 304 #define pktqavail(pq) pktq_avail((pq)) 305 #define pktqfull(pq) pktq_full((pq)) 306 #define pktqfilter(pq, fltr, fltr_ctx, defer, defer_ctx, flush, flush_ctx) \ 307 pktq_pfilter((pq), 0, (fltr), (fltr_ctx), (defer), (defer_ctx), (flush), \ 308 (flush_ctx)) 309 310 /* operations for simple non-precedence queues */ 311 #define spktenq(spq, p) spktq_enq((spq), (p)) 312 #define spktenq_head(spq, p) spktq_enq_head((spq), (p)) 313 #define spktdeq(spq) spktq_deq((spq)) 314 #define spktdeq_tail(spq) spktq_deq_tail((spq)) 315 #define spktqflush(osh, spq, dir) spktq_flush((osh), (spq), (dir)) 316 #define spktqinit(spq, max_pkts) spktq_init((spq), (max_pkts)) 317 #define spktqdeinit(spq) spktq_deinit((spq)) 318 #define spktqavail(spq) spktq_avail((spq)) 319 #define spktqfull(spq) spktq_full((spq)) 320 321 #define spktqfilter(spq, fltr, fltr_ctx, defer, defer_ctx, flush, flush_ctx) \ 322 spktq_filter((spq), (fltr), (fltr_ctx), (defer), (defer_ctx), (flush), \ 323 (flush_ctx)) 324 extern bool pktq_init(struct pktq *pq, int num_prec, int max_pkts); 325 extern bool pktq_deinit(struct pktq *pq); 326 extern bool spktq_init(struct spktq *spq, int max_pkts); 327 extern bool spktq_deinit(struct spktq *spq); 328 329 extern void pktq_set_max_plen(struct pktq *pq, int prec, int max_pkts); 330 331 /* prec_out may be NULL if caller is not interested in return value */ 332 extern void *pktq_deq(struct pktq *pq, int *prec_out); 333 extern void *pktq_deq_tail(struct pktq *pq, int *prec_out); 334 extern void *pktq_peek(struct pktq *pq, int *prec_out); 335 extern void *spktq_peek(struct spktq *spq); 336 extern void *pktq_peek_tail(struct pktq *pq, int *prec_out); 337 338 /** flush pktq */ 339 extern void pktq_flush(osl_t *osh, struct pktq *pq, bool dir); 340 extern void spktq_flush(osl_t *osh, struct spktq *spq, bool dir); 341 /** Empty the queue at particular precedence level */ 342 extern void pktq_pflush(osl_t *osh, struct pktq *pq, int prec, bool dir); 343 344 #ifdef __cplusplus 345 } 346 #endif // endif 347 348 #endif /* _hnd_pktq_h_ */ 349