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