hnd_pktq.h 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  1. /*
  2. * HND generic pktq operation primitives
  3. *
  4. * Portions of this code are copyright (c) 2020 Cypress Semiconductor Corporation
  5. *
  6. * Copyright (C) 1999-2020, Broadcom Corporation
  7. *
  8. * Unless you and Broadcom execute a separate written software license
  9. * agreement governing use of this software, this software is licensed to you
  10. * under the terms of the GNU General Public License version 2 (the "GPL"),
  11. * available at http://www.broadcom.com/licenses/GPLv2.php, with the
  12. * following added to such license:
  13. *
  14. * As a special exception, the copyright holders of this software give you
  15. * permission to link this software with independent modules, and to copy and
  16. * distribute the resulting executable under terms of your choice, provided that
  17. * you also meet, for each linked independent module, the terms and conditions of
  18. * the license of that module. An independent module is a module which is not
  19. * derived from this software. The special exception does not apply to any
  20. * modifications of the software.
  21. *
  22. * Notwithstanding the above, under no circumstances may you combine this
  23. * software in any way with any other Broadcom software provided under a license
  24. * other than the GPL, without Broadcom's express prior written consent.
  25. *
  26. *
  27. * <<Broadcom-WL-IPTag/Open:>>
  28. *
  29. * $Id: hnd_pktq.h 698847 2017-05-11 00:10:48Z $
  30. */
  31. #ifndef _hnd_pktq_h_
  32. #define _hnd_pktq_h_
  33. #include <osl_ext.h>
  34. #ifdef __cplusplus
  35. extern "C" {
  36. #endif // endif
  37. /* mutex macros for thread safe */
  38. #ifdef HND_PKTQ_THREAD_SAFE
  39. #define HND_PKTQ_MUTEX_DECL(mutex) OSL_EXT_MUTEX_DECL(mutex)
  40. #else
  41. #define HND_PKTQ_MUTEX_DECL(mutex)
  42. #endif // endif
  43. /* osl multi-precedence packet queue */
  44. #define PKTQ_LEN_MAX 0xFFFF /* Max uint16 65535 packets */
  45. #ifndef PKTQ_LEN_DEFAULT
  46. #define PKTQ_LEN_DEFAULT 128 /* Max 128 packets */
  47. #endif // endif
  48. #ifndef PKTQ_MAX_PREC
  49. #define PKTQ_MAX_PREC 16 /* Maximum precedence levels */
  50. #endif // endif
  51. /** Queue for a single precedence level */
  52. typedef struct pktq_prec {
  53. void *head; /**< first packet to dequeue */
  54. void *tail; /**< last packet to dequeue */
  55. uint16 n_pkts; /**< number of queued packets */
  56. uint16 max_pkts; /**< maximum number of queued packets */
  57. uint16 stall_count; /**< # seconds since no packets are dequeued */
  58. uint16 dequeue_count; /**< # of packets dequeued in last 1 second */
  59. } pktq_prec_t;
  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. #define PKTQ_LOG_COMMON \
  98. uint32 pps_time; /**< time spent in ps pretend state */ \
  99. uint32 _prec_log;
  100. typedef struct {
  101. PKTQ_LOG_COMMON
  102. pktq_counters_t* _prec_cnt[PKTQ_MAX_PREC]; /**< Counters per queue */
  103. } pktq_log_t;
  104. #else
  105. typedef struct pktq_log pktq_log_t;
  106. #endif /* PKTQ_LOG */
  107. #define PKTQ_COMMON \
  108. HND_PKTQ_MUTEX_DECL(mutex) \
  109. pktq_log_t *pktqlog; \
  110. uint16 num_prec; /**< number of precedences in use */ \
  111. uint16 hi_prec; /**< rapid dequeue hint (>= highest non-empty prec) */ \
  112. uint16 max_pkts; /**< max packets */ \
  113. uint16 n_pkts_tot; /**< total (cummulative over all precedences) number of packets */
  114. /** multi-priority packet queue */
  115. struct pktq {
  116. PKTQ_COMMON
  117. /* q array must be last since # of elements can be either PKTQ_MAX_PREC or 1 */
  118. struct pktq_prec q[PKTQ_MAX_PREC];
  119. };
  120. /** simple, non-priority packet queue */
  121. struct spktq {
  122. HND_PKTQ_MUTEX_DECL(mutex)
  123. struct pktq_prec q;
  124. };
  125. #define PKTQ_PREC_ITER(pq, prec) for (prec = (pq)->num_prec - 1; prec >= 0; prec--)
  126. /* fn(pkt, arg). return true if pkt belongs to bsscfg */
  127. typedef bool (*ifpkt_cb_t)(void*, int);
  128. /*
  129. * pktq filter support
  130. */
  131. /** filter function return values */
  132. typedef enum {
  133. PKT_FILTER_NOACTION = 0, /**< restore the pkt to its position in the queue */
  134. PKT_FILTER_DELETE = 1, /**< delete the pkt */
  135. PKT_FILTER_REMOVE = 2, /**< do not restore the pkt to the queue,
  136. * filter fn has taken ownership of the pkt
  137. */
  138. } pktq_filter_result_t;
  139. /**
  140. * Caller supplied filter function to pktq_pfilter(), pktq_filter().
  141. * Function filter(ctx, pkt) is called with its ctx pointer on each pkt in the
  142. * pktq. When the filter function is called, the supplied pkt will have been
  143. * unlinked from the pktq. The filter function returns a pktq_filter_result_t
  144. * result specifying the action pktq_filter()/pktq_pfilter() should take for
  145. * the pkt.
  146. * Here are the actions taken by pktq_filter/pfilter() based on the supplied
  147. * filter function's return value:
  148. *
  149. * PKT_FILTER_NOACTION - The filter will re-link the pkt at its
  150. * previous location.
  151. *
  152. * PKT_FILTER_DELETE - The filter will not relink the pkt and will
  153. * call the user supplied defer_free_pkt fn on the packet.
  154. *
  155. * PKT_FILTER_REMOVE - The filter will not relink the pkt. The supplied
  156. * filter fn took ownership (or deleted) the pkt.
  157. *
  158. * WARNING: pkts inserted by the user (in pkt_filter and/or flush callbacks
  159. * and chains) in the prec queue will not be seen by the filter, and the prec
  160. * queue will be temporarily be removed from the queue hence there're side
  161. * effects including pktq_n_pkts_tot() on the queue won't reflect the correct number
  162. * of packets in the queue.
  163. */
  164. typedef pktq_filter_result_t (*pktq_filter_t)(void* ctx, void* pkt);
  165. /**
  166. * The defer_free_pkt callback is invoked when the the pktq_filter callback
  167. * returns PKT_FILTER_DELETE decision, which allows the user to deposite
  168. * the packet appropriately based on the situation (free the packet or
  169. * save it in a temporary queue etc.).
  170. */
  171. typedef void (*defer_free_pkt_fn_t)(void *ctx, void *pkt);
  172. /**
  173. * The flush_free_pkt callback is invoked when all packets in the pktq
  174. * are processed.
  175. */
  176. typedef void (*flush_free_pkt_fn_t)(void *ctx);
  177. #if defined(WLAMPDU_MAC) && defined(PROP_TXSTATUS)
  178. /* this callback will be invoked when in low_txq_scb flush()
  179. * two back-to-back pkts has same epoch value.
  180. */
  181. typedef void (*flip_epoch_t)(void *ctx, void *pkt, uint8 *flipEpoch, uint8 *lastEpoch);
  182. #endif /* defined(WLAMPDU_MAC) && defined(PROP_TXSTATUS) */
  183. /** filter a pktq, using the caller supplied filter/deposition/flush functions */
  184. extern void pktq_filter(struct pktq *pq, pktq_filter_t fn, void* arg,
  185. defer_free_pkt_fn_t defer, void *defer_ctx, flush_free_pkt_fn_t flush, void *flush_ctx);
  186. /** filter a particular precedence in pktq, using the caller supplied filter function */
  187. extern void pktq_pfilter(struct pktq *pq, int prec, pktq_filter_t fn, void* arg,
  188. defer_free_pkt_fn_t defer, void *defer_ctx, flush_free_pkt_fn_t flush, void *flush_ctx);
  189. /** filter a simple non-precedence in spktq, using the caller supplied filter function */
  190. extern void spktq_filter(struct spktq *spq, pktq_filter_t fltr, void* fltr_ctx,
  191. defer_free_pkt_fn_t defer, void *defer_ctx, flush_free_pkt_fn_t flush, void *flush_ctx);
  192. /* operations on a specific precedence in packet queue */
  193. #define pktqprec_max_pkts(pq, prec) ((pq)->q[prec].max_pkts)
  194. #define pktqprec_n_pkts(pq, prec) ((pq)->q[prec].n_pkts)
  195. #define pktqprec_empty(pq, prec) ((pq)->q[prec].n_pkts == 0)
  196. #define pktqprec_peek(pq, prec) ((pq)->q[prec].head)
  197. #define pktqprec_peek_tail(pq, prec) ((pq)->q[prec].tail)
  198. #define spktq_peek_tail(pq) ((pq)->q.tail)
  199. #ifdef HND_PKTQ_THREAD_SAFE
  200. extern int pktqprec_avail_pkts(struct pktq *pq, int prec);
  201. extern bool pktqprec_full(struct pktq *pq, int prec);
  202. #else
  203. #define pktqprec_avail_pkts(pq, prec) ((pq)->q[prec].max_pkts - (pq)->q[prec].n_pkts)
  204. #define pktqprec_full(pq, prec) ((pq)->q[prec].n_pkts >= (pq)->q[prec].max_pkts)
  205. #endif /* HND_PKTQ_THREAD_SAFE */
  206. extern void pktq_append(struct pktq *pq, int prec, struct spktq *list);
  207. extern void spktq_append(struct spktq *spq, struct spktq *list);
  208. extern void pktq_prepend(struct pktq *pq, int prec, struct spktq *list);
  209. extern void spktq_prepend(struct spktq *spq, struct spktq *list);
  210. extern void *pktq_penq(struct pktq *pq, int prec, void *p);
  211. extern void *pktq_penq_head(struct pktq *pq, int prec, void *p);
  212. extern void *pktq_pdeq(struct pktq *pq, int prec);
  213. extern void *pktq_pdeq_prev(struct pktq *pq, int prec, void *prev_p);
  214. extern void *pktq_pdeq_with_fn(struct pktq *pq, int prec, ifpkt_cb_t fn, int arg);
  215. extern void *pktq_pdeq_tail(struct pktq *pq, int prec);
  216. /** Remove a specified packet from its queue */
  217. extern bool pktq_pdel(struct pktq *pq, void *p, int prec);
  218. /* For single precedence queues */
  219. extern void *spktq_enq(struct spktq *spq, void *p);
  220. extern void *spktq_enq_head(struct spktq *spq, void *p);
  221. extern void *spktq_deq(struct spktq *spq);
  222. extern void *spktq_deq_tail(struct spktq *spq);
  223. /* operations on a set of precedences in packet queue */
  224. extern int pktq_mlen(struct pktq *pq, uint prec_bmp);
  225. extern void *pktq_mdeq(struct pktq *pq, uint prec_bmp, int *prec_out);
  226. extern void *pktq_mpeek(struct pktq *pq, uint prec_bmp, int *prec_out);
  227. /* operations on packet queue as a whole */
  228. #define pktq_n_pkts_tot(pq) ((int)(pq)->n_pkts_tot)
  229. #define pktq_max(pq) ((int)(pq)->max_pkts)
  230. #define pktq_empty(pq) ((pq)->n_pkts_tot == 0)
  231. #define spktq_n_pkts(spq) ((int)(spq)->q.n_pkts)
  232. #define spktq_empty(spq) ((spq)->q.n_pkts == 0)
  233. #define spktq_max(spq) ((int)(spq)->q.max_pkts)
  234. #define spktq_empty(spq) ((spq)->q.n_pkts == 0)
  235. #ifdef HND_PKTQ_THREAD_SAFE
  236. extern int pktq_avail(struct pktq *pq);
  237. extern bool pktq_full(struct pktq *pq);
  238. extern int spktq_avail(struct spktq *spq);
  239. extern bool spktq_full(struct spktq *spq);
  240. #else
  241. #define pktq_avail(pq) ((int)((pq)->max_pkts - (pq)->n_pkts_tot))
  242. #define pktq_full(pq) ((pq)->n_pkts_tot >= (pq)->max_pkts)
  243. #define spktq_avail(spq) ((int)((spq)->q.max_pkts - (spq)->q.n_pkts))
  244. #define spktq_full(spq) ((spq)->q.n_pkts >= (spq)->q.max_pkts)
  245. #endif /* HND_PKTQ_THREAD_SAFE */
  246. /* operations for single precedence queues */
  247. #define pktenq(pq, p) pktq_penq((pq), 0, (p))
  248. #define pktenq_head(pq, p) pktq_penq_head((pq), 0, (p))
  249. #define pktdeq(pq) pktq_pdeq((pq), 0)
  250. #define pktdeq_tail(pq) pktq_pdeq_tail((pq), 0)
  251. #define pktqflush(osh, pq, dir) pktq_pflush(osh, (pq), 0, (dir))
  252. #define pktqinit(pq, max_pkts) pktq_init((pq), 1, (max_pkts))
  253. #define pktqdeinit(pq) pktq_deinit((pq))
  254. #define pktqavail(pq) pktq_avail((pq))
  255. #define pktqfull(pq) pktq_full((pq))
  256. #define pktqfilter(pq, fltr, fltr_ctx, defer, defer_ctx, flush, flush_ctx) \
  257. pktq_pfilter((pq), 0, (fltr), (fltr_ctx), (defer), (defer_ctx), (flush), (flush_ctx))
  258. /* operations for simple non-precedence queues */
  259. #define spktenq(spq, p) spktq_enq((spq), (p))
  260. #define spktenq_head(spq, p) spktq_enq_head((spq), (p))
  261. #define spktdeq(spq) spktq_deq((spq))
  262. #define spktdeq_tail(spq) spktq_deq_tail((spq))
  263. #define spktqflush(osh, spq, dir) spktq_flush((osh), (spq), (dir))
  264. #define spktqinit(spq, max_pkts) spktq_init((spq), (max_pkts))
  265. #define spktqdeinit(spq) spktq_deinit((spq))
  266. #define spktqavail(spq) spktq_avail((spq))
  267. #define spktqfull(spq) spktq_full((spq))
  268. #define spktqfilter(spq, fltr, fltr_ctx, defer, defer_ctx, flush, flush_ctx) \
  269. spktq_filter((spq), (fltr), (fltr_ctx), (defer), (defer_ctx), (flush), (flush_ctx))
  270. extern bool pktq_init(struct pktq *pq, int num_prec, int max_pkts);
  271. extern bool pktq_deinit(struct pktq *pq);
  272. extern bool spktq_init(struct spktq *spq, int max_pkts);
  273. extern bool spktq_deinit(struct spktq *spq);
  274. extern void pktq_set_max_plen(struct pktq *pq, int prec, int max_pkts);
  275. /* prec_out may be NULL if caller is not interested in return value */
  276. extern void *pktq_deq(struct pktq *pq, int *prec_out);
  277. extern void *pktq_deq_tail(struct pktq *pq, int *prec_out);
  278. extern void *pktq_peek(struct pktq *pq, int *prec_out);
  279. extern void *spktq_peek(struct spktq *spq);
  280. extern void *pktq_peek_tail(struct pktq *pq, int *prec_out);
  281. /** flush pktq */
  282. extern void pktq_flush(osl_t *osh, struct pktq *pq, bool dir);
  283. extern void spktq_flush(osl_t *osh, struct spktq *spq, bool dir);
  284. /** Empty the queue at particular precedence level */
  285. extern void pktq_pflush(osl_t *osh, struct pktq *pq, int prec, bool dir);
  286. #ifdef __cplusplus
  287. }
  288. #endif // endif
  289. #endif /* _hnd_pktq_h_ */