• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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