1 /*
2 * Copyright (c) 2011-2020 The Linux Foundation. All rights reserved.
3 * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
4 *
5 * Permission to use, copy, modify, and/or distribute this software for
6 * any purpose with or without fee is hereby granted, provided that the
7 * above copyright notice and this permission notice appear in all
8 * copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
18 */
19
20 /*=== header file includes ===*/
21 /* generic utilities */
22 #include <qdf_nbuf.h> /* qdf_nbuf_t, etc. */
23 #include <qdf_mem.h> /* qdf_mem_malloc */
24
25 /* external interfaces */
26 #include <ol_txrx_api.h> /* ol_txrx_pdev_handle */
27 #include <ol_txrx_htt_api.h> /* ol_rx_addba_handler, etc. */
28 #include <ol_ctrl_txrx_api.h> /* ol_ctrl_rx_addba_complete */
29 #include <ol_htt_rx_api.h> /* htt_rx_desc_frame_free */
30 #include <ol_ctrl_txrx_api.h> /* ol_rx_err */
31
32 /* datapath internal interfaces */
33 #include <ol_txrx_peer_find.h> /* ol_txrx_peer_find_by_id */
34 #include <ol_txrx_internal.h> /* TXRX_ASSERT */
35 #include <ol_rx_reorder_timeout.h> /* OL_RX_REORDER_TIMEOUT_REMOVE, etc. */
36 #include <ol_rx_reorder.h>
37 #include <ol_rx_defrag.h>
38
39 /*=== data types and defines ===*/
40 #define OL_RX_REORDER_ROUND_PWR2(value) g_log2ceil[value]
41
42 /*=== global variables ===*/
43
44 static char g_log2ceil[] = {
45 1, /* 0 -> 1 */
46 1, /* 1 -> 1 */
47 2, /* 2 -> 2 */
48 4, 4, /* 3-4 -> 4 */
49 8, 8, 8, 8, /* 5-8 -> 8 */
50 16, 16, 16, 16, 16, 16, 16, 16, /* 9-16 -> 16 */
51 32, 32, 32, 32, 32, 32, 32, 32,
52 32, 32, 32, 32, 32, 32, 32, 32, /* 17-32 -> 32 */
53 64, 64, 64, 64, 64, 64, 64, 64,
54 64, 64, 64, 64, 64, 64, 64, 64,
55 64, 64, 64, 64, 64, 64, 64, 64,
56 64, 64, 64, 64, 64, 64, 64, 64, /* 33-64 -> 64 */
57 };
58
59 /*=== function definitions ===*/
60
61 /*---*/
62
63 #define QCA_SUPPORT_RX_REORDER_RELEASE_CHECK 0
64 #define OL_RX_REORDER_IDX_START_SELF_SELECT(peer, tid, idx_start) /* no-op */
65 #define OL_RX_REORDER_IDX_WRAP(idx, win_sz, win_sz_mask) { idx &= win_sz_mask; }
66 #define OL_RX_REORDER_IDX_MAX(win_sz, win_sz_mask) win_sz_mask
67 #define OL_RX_REORDER_IDX_INIT(seq_num, win_sz, win_sz_mask) 0 /* n/a */
68 #define OL_RX_REORDER_NO_HOLES(rx_reorder) 0
69 #define OL_RX_REORDER_MPDU_CNT_INCR(rx_reorder, incr) /* n/a */
70 #define OL_RX_REORDER_MPDU_CNT_DECR(rx_reorder, decr) /* n/a */
71
72 /*---*/
73
74 /* reorder array elements are known to be non-NULL */
75 #define OL_RX_REORDER_LIST_APPEND(head_msdu, tail_msdu, rx_reorder_array_elem) \
76 do { \
77 if (tail_msdu) { \
78 qdf_nbuf_set_next(tail_msdu, \
79 rx_reorder_array_elem->head); \
80 } \
81 } while (0)
82
83 /* functions called by txrx components */
84
ol_rx_reorder_init(struct ol_rx_reorder_t * rx_reorder,uint8_t tid)85 void ol_rx_reorder_init(struct ol_rx_reorder_t *rx_reorder, uint8_t tid)
86 {
87 rx_reorder->win_sz = 1;
88 rx_reorder->win_sz_mask = 0;
89 rx_reorder->array = &rx_reorder->base;
90 rx_reorder->base.head = rx_reorder->base.tail = NULL;
91 rx_reorder->tid = tid;
92 rx_reorder->defrag_timeout_ms = 0;
93
94 rx_reorder->defrag_waitlist_elem.tqe_next = NULL;
95 rx_reorder->defrag_waitlist_elem.tqe_prev = NULL;
96 }
97
98 static enum htt_rx_status
ol_rx_reorder_seq_num_check(struct ol_txrx_pdev_t * pdev,struct ol_txrx_peer_t * peer,unsigned int tid,unsigned int seq_num)99 ol_rx_reorder_seq_num_check(
100 struct ol_txrx_pdev_t *pdev,
101 struct ol_txrx_peer_t *peer,
102 unsigned int tid, unsigned int seq_num)
103 {
104 unsigned int seq_num_delta;
105
106 /* don't check the new seq_num against last_seq
107 if last_seq is not valid */
108 if (peer->tids_last_seq[tid] == IEEE80211_SEQ_MAX)
109 return htt_rx_status_ok;
110
111 /*
112 * For duplicate detection, it might be helpful to also check
113 * whether the retry bit is set or not - a strict duplicate packet
114 * should be the one with retry bit set.
115 * However, since many implementations do not set the retry bit,
116 * and since this same function is also used for filtering out
117 * late-arriving frames (frames that arrive after their rx reorder
118 * timeout has expired) which are not retries, don't bother checking
119 * the retry bit for now.
120 */
121 /* note: if new seq_num == old seq_num, seq_num_delta = 4095 */
122 seq_num_delta = (seq_num - 1 - peer->tids_last_seq[tid]) &
123 (IEEE80211_SEQ_MAX - 1); /* account for wraparound */
124
125 if (seq_num_delta > (IEEE80211_SEQ_MAX >> 1)) {
126 return htt_rx_status_err_replay;
127 /* or maybe htt_rx_status_err_dup */
128 }
129 return htt_rx_status_ok;
130 }
131
132 /**
133 * ol_rx_seq_num_check() - Does duplicate detection for mcast packets and
134 * duplicate detection & check for out-of-order
135 * packets for unicast packets.
136 * @pdev: Pointer to pdev maintained by OL
137 * @peer: Pointer to peer structure maintained by OL
138 * @tid: TID value passed as part of HTT msg by f/w
139 * @rx_mpdu_desc: Pointer to Rx Descriptor for the given MPDU
140 *
141 * This function
142 * 1) For Multicast Frames -- does duplicate detection
143 * A frame is considered duplicate & dropped if it has a seq.number
144 * which is received twice in succession and with the retry bit set
145 * in the second case.
146 * A frame which is older than the last sequence number received
147 * is not considered duplicate but out-of-order. This function does
148 * perform out-of-order check for multicast frames, which is in
149 * keeping with the 802.11 2012 spec section 9.3.2.10
150 * 2) For Unicast Frames -- does duplicate detection & out-of-order check
151 * only for non-aggregation tids.
152 *
153 * Return: Returns htt_rx_status_err_replay, if packet needs to be
154 * dropped, htt_rx_status_ok otherwise.
155 */
156 enum htt_rx_status
ol_rx_seq_num_check(struct ol_txrx_pdev_t * pdev,struct ol_txrx_peer_t * peer,uint8_t tid,void * rx_mpdu_desc)157 ol_rx_seq_num_check(struct ol_txrx_pdev_t *pdev,
158 struct ol_txrx_peer_t *peer,
159 uint8_t tid,
160 void *rx_mpdu_desc)
161 {
162 uint16_t pkt_tid = 0xffff;
163 uint16_t seq_num = IEEE80211_SEQ_MAX;
164 bool retry = 0;
165
166 seq_num = htt_rx_mpdu_desc_seq_num(pdev->htt_pdev, rx_mpdu_desc, false);
167
168 /* For mcast packets, we only the dup-detection, not re-order check */
169
170 if (qdf_unlikely(OL_RX_MCAST_TID == tid)) {
171
172 pkt_tid = htt_rx_mpdu_desc_tid(pdev->htt_pdev, rx_mpdu_desc);
173
174 /* Invalid packet TID, expected only for HL */
175 /* Pass the packet on */
176 if (qdf_unlikely(pkt_tid >= OL_TXRX_NUM_EXT_TIDS))
177 return htt_rx_status_ok;
178
179 retry = htt_rx_mpdu_desc_retry(pdev->htt_pdev, rx_mpdu_desc);
180
181 /*
182 * At this point, we define frames to be duplicate if they
183 * arrive "ONLY" in succession with the same sequence number
184 * and the last one has the retry bit set. For an older frame,
185 * we consider that as an out of order frame, and hence do not
186 * perform the dup-detection or out-of-order check for multicast
187 * frames as per discussions & spec.
188 * Hence "seq_num <= last_seq_num" check is not necessary.
189 */
190 if (qdf_unlikely(retry &&
191 (seq_num == peer->tids_mcast_last_seq[pkt_tid]))) {
192 /* drop mcast */
193 TXRX_STATS_INCR(pdev, priv.rx.err.msdu_mc_dup_drop);
194 return htt_rx_status_err_replay;
195 }
196
197 /*
198 * This is a multicast packet likely to be passed on...
199 * Set the mcast last seq number here
200 * This is fairly accurate since:
201 * a) f/w sends multicast as separate PPDU/HTT messages
202 * b) Mcast packets are not aggregated & hence single
203 * c) Result of b) is that, flush / release bit is set
204 * always on the mcast packets, so likely to be
205 * immediatedly released.
206 */
207 peer->tids_mcast_last_seq[pkt_tid] = seq_num;
208 return htt_rx_status_ok;
209 } else
210 return ol_rx_reorder_seq_num_check(pdev, peer, tid, seq_num);
211 }
212
213
214 void
ol_rx_reorder_store(struct ol_txrx_pdev_t * pdev,struct ol_txrx_peer_t * peer,unsigned int tid,unsigned int idx,qdf_nbuf_t head_msdu,qdf_nbuf_t tail_msdu)215 ol_rx_reorder_store(struct ol_txrx_pdev_t *pdev,
216 struct ol_txrx_peer_t *peer,
217 unsigned int tid,
218 unsigned int idx, qdf_nbuf_t head_msdu,
219 qdf_nbuf_t tail_msdu)
220 {
221 struct ol_rx_reorder_array_elem_t *rx_reorder_array_elem;
222
223 idx &= peer->tids_rx_reorder[tid].win_sz_mask;
224 rx_reorder_array_elem = &peer->tids_rx_reorder[tid].array[idx];
225 if (rx_reorder_array_elem->head) {
226 qdf_nbuf_set_next(rx_reorder_array_elem->tail, head_msdu);
227 } else {
228 rx_reorder_array_elem->head = head_msdu;
229 OL_RX_REORDER_MPDU_CNT_INCR(&peer->tids_rx_reorder[tid], 1);
230 }
231 rx_reorder_array_elem->tail = tail_msdu;
232 }
233
234 void
ol_rx_reorder_release(struct ol_txrx_vdev_t * vdev,struct ol_txrx_peer_t * peer,unsigned int tid,unsigned int idx_start,unsigned int idx_end)235 ol_rx_reorder_release(struct ol_txrx_vdev_t *vdev,
236 struct ol_txrx_peer_t *peer,
237 unsigned int tid, unsigned int idx_start,
238 unsigned int idx_end)
239 {
240 unsigned int idx;
241 unsigned int win_sz, win_sz_mask;
242 struct ol_rx_reorder_array_elem_t *rx_reorder_array_elem;
243 qdf_nbuf_t head_msdu;
244 qdf_nbuf_t tail_msdu;
245
246 OL_RX_REORDER_IDX_START_SELF_SELECT(peer, tid, &idx_start);
247 /* may get reset below */
248 peer->tids_next_rel_idx[tid] = (uint16_t) idx_end;
249
250 win_sz = peer->tids_rx_reorder[tid].win_sz;
251 win_sz_mask = peer->tids_rx_reorder[tid].win_sz_mask;
252 idx_start &= win_sz_mask;
253 idx_end &= win_sz_mask;
254 rx_reorder_array_elem = &peer->tids_rx_reorder[tid].array[idx_start];
255
256 head_msdu = rx_reorder_array_elem->head;
257 tail_msdu = rx_reorder_array_elem->tail;
258 rx_reorder_array_elem->head = rx_reorder_array_elem->tail = NULL;
259 if (head_msdu)
260 OL_RX_REORDER_MPDU_CNT_DECR(&peer->tids_rx_reorder[tid], 1);
261
262 idx = (idx_start + 1);
263 OL_RX_REORDER_IDX_WRAP(idx, win_sz, win_sz_mask);
264 while (idx != idx_end) {
265 rx_reorder_array_elem = &peer->tids_rx_reorder[tid].array[idx];
266 if (rx_reorder_array_elem->head) {
267 OL_RX_REORDER_MPDU_CNT_DECR(&peer->tids_rx_reorder[tid],
268 1);
269 OL_RX_REORDER_LIST_APPEND(head_msdu, tail_msdu,
270 rx_reorder_array_elem);
271 tail_msdu = rx_reorder_array_elem->tail;
272 }
273 rx_reorder_array_elem->head = rx_reorder_array_elem->tail =
274 NULL;
275 idx++;
276 OL_RX_REORDER_IDX_WRAP(idx, win_sz, win_sz_mask);
277 }
278 if (head_msdu) {
279 uint16_t seq_num;
280 htt_pdev_handle htt_pdev = vdev->pdev->htt_pdev;
281
282 /*
283 * This logic is not quite correct - the last_seq value should
284 * be the sequence number of the final MPDU released rather than
285 * the initial MPDU released.
286 * However, tracking the sequence number of the first MPDU in
287 * the released batch works well enough:
288 * For Peregrine and Rome, the last_seq is checked only for
289 * non-aggregate cases, where only one MPDU at a time is
290 * released.
291 * For Riva, Pronto, and Northstar, the last_seq is checked to
292 * filter out late-arriving rx frames, whose sequence number
293 * will be less than the first MPDU in this release batch.
294 */
295 seq_num = htt_rx_mpdu_desc_seq_num(
296 htt_pdev,
297 htt_rx_msdu_desc_retrieve(htt_pdev,
298 head_msdu), false);
299 peer->tids_last_seq[tid] = seq_num;
300 /* rx_opt_proc takes a NULL-terminated list of msdu netbufs */
301 qdf_nbuf_set_next(tail_msdu, NULL);
302 peer->rx_opt_proc(vdev, peer, tid, head_msdu);
303 }
304 /*
305 * If the rx reorder timeout is handled by host SW rather than the
306 * target's rx reorder logic, then stop the timer here.
307 * (If there are remaining rx holes, then the timer will be restarted.)
308 */
309 OL_RX_REORDER_TIMEOUT_REMOVE(peer, tid);
310 }
311
312 void
ol_rx_reorder_flush(struct ol_txrx_vdev_t * vdev,struct ol_txrx_peer_t * peer,unsigned int tid,unsigned int idx_start,unsigned int idx_end,enum htt_rx_flush_action action)313 ol_rx_reorder_flush(struct ol_txrx_vdev_t *vdev,
314 struct ol_txrx_peer_t *peer,
315 unsigned int tid,
316 unsigned int idx_start,
317 unsigned int idx_end, enum htt_rx_flush_action action)
318 {
319 struct ol_txrx_pdev_t *pdev;
320 unsigned int win_sz;
321 uint8_t win_sz_mask;
322 struct ol_rx_reorder_array_elem_t *rx_reorder_array_elem;
323 qdf_nbuf_t head_msdu = NULL;
324 qdf_nbuf_t tail_msdu = NULL;
325
326 pdev = vdev->pdev;
327 win_sz = peer->tids_rx_reorder[tid].win_sz;
328 win_sz_mask = peer->tids_rx_reorder[tid].win_sz_mask;
329
330 OL_RX_REORDER_IDX_START_SELF_SELECT(peer, tid, &idx_start);
331 /* a idx_end value of 0xffff means to flush the entire array */
332 if (idx_end == 0xffff) {
333 idx_end = idx_start;
334 /*
335 * The array is being flushed in entirety because the block
336 * ack window has been shifted to a new position that does not
337 * overlap with the old position. (Or due to reception of a
338 * DELBA.)
339 * Thus, since the block ack window is essentially being reset,
340 * reset the "next release index".
341 */
342 peer->tids_next_rel_idx[tid] =
343 OL_RX_REORDER_IDX_INIT(0 /*n/a */, win_sz, win_sz_mask);
344 } else {
345 peer->tids_next_rel_idx[tid] = (uint16_t) idx_end;
346 }
347
348 idx_start &= win_sz_mask;
349 idx_end &= win_sz_mask;
350
351 do {
352 rx_reorder_array_elem =
353 &peer->tids_rx_reorder[tid].array[idx_start];
354 idx_start = (idx_start + 1);
355 OL_RX_REORDER_IDX_WRAP(idx_start, win_sz, win_sz_mask);
356
357 if (rx_reorder_array_elem->head) {
358 OL_RX_REORDER_MPDU_CNT_DECR(&peer->tids_rx_reorder[tid],
359 1);
360 if (!head_msdu) {
361 head_msdu = rx_reorder_array_elem->head;
362 tail_msdu = rx_reorder_array_elem->tail;
363 rx_reorder_array_elem->head = NULL;
364 rx_reorder_array_elem->tail = NULL;
365 continue;
366 }
367 qdf_nbuf_set_next(tail_msdu,
368 rx_reorder_array_elem->head);
369 tail_msdu = rx_reorder_array_elem->tail;
370 rx_reorder_array_elem->head =
371 rx_reorder_array_elem->tail = NULL;
372 }
373 } while (idx_start != idx_end);
374
375 ol_rx_defrag_waitlist_remove(peer, tid);
376
377 if (head_msdu) {
378 uint16_t seq_num;
379 htt_pdev_handle htt_pdev = vdev->pdev->htt_pdev;
380
381 seq_num = htt_rx_mpdu_desc_seq_num(
382 htt_pdev,
383 htt_rx_msdu_desc_retrieve(htt_pdev, head_msdu), false);
384 peer->tids_last_seq[tid] = seq_num;
385 /* rx_opt_proc takes a NULL-terminated list of msdu netbufs */
386 qdf_nbuf_set_next(tail_msdu, NULL);
387 if (action == htt_rx_flush_release) {
388 peer->rx_opt_proc(vdev, peer, tid, head_msdu);
389 } else {
390 do {
391 qdf_nbuf_t next;
392
393 next = qdf_nbuf_next(head_msdu);
394 htt_rx_desc_frame_free(pdev->htt_pdev,
395 head_msdu);
396 head_msdu = next;
397 } while (head_msdu);
398 }
399 }
400 /*
401 * If the rx reorder array is empty, then reset the last_seq value -
402 * it is likely that a BAR or a sequence number shift caused the
403 * sequence number to jump, so the old last_seq value is not relevant.
404 */
405 if (OL_RX_REORDER_NO_HOLES(&peer->tids_rx_reorder[tid]))
406 peer->tids_last_seq[tid] = IEEE80211_SEQ_MAX; /* invalid */
407
408 OL_RX_REORDER_TIMEOUT_REMOVE(peer, tid);
409 }
410
411 void
ol_rx_reorder_first_hole(struct ol_txrx_peer_t * peer,unsigned int tid,unsigned int * idx_end)412 ol_rx_reorder_first_hole(struct ol_txrx_peer_t *peer,
413 unsigned int tid, unsigned int *idx_end)
414 {
415 unsigned int win_sz, win_sz_mask;
416 unsigned int idx_start = 0, tmp_idx = 0;
417
418 win_sz = peer->tids_rx_reorder[tid].win_sz;
419 win_sz_mask = peer->tids_rx_reorder[tid].win_sz_mask;
420
421 OL_RX_REORDER_IDX_START_SELF_SELECT(peer, tid, &idx_start);
422 tmp_idx++;
423 OL_RX_REORDER_IDX_WRAP(tmp_idx, win_sz, win_sz_mask);
424 /* bypass the initial hole */
425 while (tmp_idx != idx_start &&
426 !peer->tids_rx_reorder[tid].array[tmp_idx].head) {
427 tmp_idx++;
428 OL_RX_REORDER_IDX_WRAP(tmp_idx, win_sz, win_sz_mask);
429 }
430 /* bypass the present frames following the initial hole */
431 while (tmp_idx != idx_start &&
432 peer->tids_rx_reorder[tid].array[tmp_idx].head) {
433 tmp_idx++;
434 OL_RX_REORDER_IDX_WRAP(tmp_idx, win_sz, win_sz_mask);
435 }
436 /*
437 * idx_end is exclusive rather than inclusive.
438 * In other words, it is the index of the first slot of the second
439 * hole, rather than the index of the final present frame following
440 * the first hole.
441 */
442 *idx_end = tmp_idx;
443 }
444
445 #ifdef HL_RX_AGGREGATION_HOLE_DETECTION
446
447 /**
448 * ol_rx_reorder_detect_hole - ol rx reorder detect hole
449 * @peer: ol_txrx_peer_t
450 * @tid: tid
451 * @idx_start: idx_start
452 *
453 * Return: void
454 */
ol_rx_reorder_detect_hole(struct ol_txrx_peer_t * peer,uint32_t tid,uint32_t idx_start)455 static void ol_rx_reorder_detect_hole(struct ol_txrx_peer_t *peer,
456 uint32_t tid,
457 uint32_t idx_start)
458 {
459 uint32_t win_sz_mask, next_rel_idx, hole_size;
460
461 if (tid >= OL_TXRX_NUM_EXT_TIDS) {
462 ol_txrx_err("Invalid tid: %u", tid);
463 return;
464 }
465
466 if (peer->tids_next_rel_idx[tid] == INVALID_REORDER_INDEX)
467 return;
468
469 win_sz_mask = peer->tids_rx_reorder[tid].win_sz_mask;
470 /* Return directly if block-ack not enable */
471 if (win_sz_mask == 0)
472 return;
473
474 idx_start &= win_sz_mask;
475 next_rel_idx = peer->tids_next_rel_idx[tid] & win_sz_mask;
476
477 if (idx_start != next_rel_idx) {
478 hole_size = ((int)idx_start - (int)next_rel_idx) & win_sz_mask;
479
480 ol_rx_aggregation_hole(hole_size);
481 }
482
483 return;
484 }
485
486 #else
487
488 /**
489 * ol_rx_reorder_detect_hole - ol rx reorder detect hole
490 * @peer: ol_txrx_peer_t
491 * @tid: tid
492 * @idx_start: idx_start
493 *
494 * Return: void
495 */
ol_rx_reorder_detect_hole(struct ol_txrx_peer_t * peer,uint32_t tid,uint32_t idx_start)496 static void ol_rx_reorder_detect_hole(struct ol_txrx_peer_t *peer,
497 uint32_t tid,
498 uint32_t idx_start)
499 {
500 /* no-op */
501 }
502
503 #endif
504
505 void
ol_rx_reorder_peer_cleanup(struct ol_txrx_vdev_t * vdev,struct ol_txrx_peer_t * peer)506 ol_rx_reorder_peer_cleanup(struct ol_txrx_vdev_t *vdev,
507 struct ol_txrx_peer_t *peer)
508 {
509 int tid;
510
511 for (tid = 0; tid < OL_TXRX_NUM_EXT_TIDS; tid++) {
512 ol_rx_reorder_flush(vdev, peer, tid, 0, 0,
513 htt_rx_flush_discard);
514 }
515 OL_RX_REORDER_TIMEOUT_PEER_CLEANUP(peer);
516 }
517
518 /* functions called by HTT */
519
520 void
ol_rx_addba_handler(ol_txrx_pdev_handle pdev,uint16_t peer_id,uint8_t tid,uint8_t win_sz,uint16_t start_seq_num,uint8_t failed)521 ol_rx_addba_handler(ol_txrx_pdev_handle pdev,
522 uint16_t peer_id,
523 uint8_t tid,
524 uint8_t win_sz, uint16_t start_seq_num, uint8_t failed)
525 {
526 uint8_t round_pwr2_win_sz;
527 unsigned int array_size;
528 struct ol_txrx_peer_t *peer;
529 struct ol_rx_reorder_t *rx_reorder;
530 void *array_mem = NULL;
531
532 if (tid >= OL_TXRX_NUM_EXT_TIDS) {
533 ol_txrx_err("invalid tid, %u", tid);
534 WARN_ON(1);
535 return;
536 }
537
538 peer = ol_txrx_peer_find_by_id(pdev, peer_id);
539 if (!peer) {
540 ol_txrx_err("not able to find peer, %u", peer_id);
541 return;
542 }
543
544 if (pdev->cfg.host_addba) {
545 ol_ctrl_rx_addba_complete(pdev->ctrl_pdev,
546 &peer->mac_addr.raw[0], tid, failed);
547 }
548 if (failed)
549 return;
550
551 peer->tids_last_seq[tid] = IEEE80211_SEQ_MAX; /* invalid */
552 rx_reorder = &peer->tids_rx_reorder[tid];
553
554 TXRX_ASSERT2(win_sz <= 64);
555 round_pwr2_win_sz = OL_RX_REORDER_ROUND_PWR2(win_sz);
556 array_size =
557 round_pwr2_win_sz * sizeof(struct ol_rx_reorder_array_elem_t);
558
559 array_mem = qdf_mem_malloc(array_size);
560 if (!array_mem)
561 return;
562
563 if (rx_reorder->array != &rx_reorder->base) {
564 ol_txrx_info("delete array for tid %d", tid);
565 qdf_mem_free(rx_reorder->array);
566 }
567
568 rx_reorder->array = array_mem;
569 rx_reorder->win_sz = win_sz;
570 TXRX_ASSERT1(rx_reorder->array);
571
572 rx_reorder->win_sz_mask = round_pwr2_win_sz - 1;
573 rx_reorder->num_mpdus = 0;
574
575 peer->tids_next_rel_idx[tid] =
576 OL_RX_REORDER_IDX_INIT(start_seq_num, rx_reorder->win_sz,
577 rx_reorder->win_sz_mask);
578 }
579
580 void
ol_rx_delba_handler(ol_txrx_pdev_handle pdev,uint16_t peer_id,uint8_t tid)581 ol_rx_delba_handler(ol_txrx_pdev_handle pdev, uint16_t peer_id, uint8_t tid)
582 {
583 struct ol_txrx_peer_t *peer;
584 struct ol_rx_reorder_t *rx_reorder;
585
586 if (tid >= OL_TXRX_NUM_EXT_TIDS) {
587 ol_txrx_err("invalid tid, %u", tid);
588 WARN_ON(1);
589 return;
590 }
591
592 peer = ol_txrx_peer_find_by_id(pdev, peer_id);
593 if (!peer) {
594 ol_txrx_err("not able to find peer, %u", peer_id);
595 return;
596 }
597
598 peer->tids_next_rel_idx[tid] = INVALID_REORDER_INDEX;
599 rx_reorder = &peer->tids_rx_reorder[tid];
600
601 /* check that there really was a block ack agreement */
602 TXRX_ASSERT1(rx_reorder->win_sz_mask != 0);
603 /*
604 * Deallocate the old rx reorder array.
605 * The call to ol_rx_reorder_init below
606 * will reset rx_reorder->array to point to
607 * the single-element statically-allocated reorder array
608 * used for non block-ack cases.
609 */
610 if (rx_reorder->array != &rx_reorder->base) {
611 ol_txrx_dbg("delete reorder array, tid:%d",
612 tid);
613 qdf_mem_free(rx_reorder->array);
614 }
615
616 /* set up the TID with default parameters (ARQ window size = 1) */
617 ol_rx_reorder_init(rx_reorder, tid);
618 }
619
620 void
ol_rx_flush_handler(ol_txrx_pdev_handle pdev,uint16_t peer_id,uint8_t tid,uint16_t idx_start,uint16_t idx_end,enum htt_rx_flush_action action)621 ol_rx_flush_handler(ol_txrx_pdev_handle pdev,
622 uint16_t peer_id,
623 uint8_t tid,
624 uint16_t idx_start,
625 uint16_t idx_end, enum htt_rx_flush_action action)
626 {
627 struct ol_txrx_vdev_t *vdev = NULL;
628 void *rx_desc;
629 struct ol_txrx_peer_t *peer;
630 int idx;
631 struct ol_rx_reorder_array_elem_t *rx_reorder_array_elem;
632 htt_pdev_handle htt_pdev = pdev->htt_pdev;
633
634 if (tid >= OL_TXRX_NUM_EXT_TIDS) {
635 ol_txrx_err("Invalid tid: %u", tid);
636 return;
637 }
638
639 peer = ol_txrx_peer_find_by_id(pdev, peer_id);
640 if (peer)
641 vdev = peer->vdev;
642 else
643 return;
644
645 OL_RX_REORDER_TIMEOUT_MUTEX_LOCK(pdev);
646
647 idx = idx_start & peer->tids_rx_reorder[tid].win_sz_mask;
648 rx_reorder_array_elem = &peer->tids_rx_reorder[tid].array[idx];
649 if (rx_reorder_array_elem->head) {
650 rx_desc =
651 htt_rx_msdu_desc_retrieve(htt_pdev,
652 rx_reorder_array_elem->head);
653 if (htt_rx_msdu_is_frag(htt_pdev, rx_desc)) {
654 ol_rx_reorder_flush_frag(htt_pdev, peer, tid,
655 idx_start);
656 /*
657 * Assuming flush message sent separately for frags
658 * and for normal frames
659 */
660 OL_RX_REORDER_TIMEOUT_MUTEX_UNLOCK(pdev);
661 return;
662 }
663 }
664
665 if (action == htt_rx_flush_release)
666 ol_rx_reorder_detect_hole(peer, tid, idx_start);
667
668 ol_rx_reorder_flush(vdev, peer, tid, idx_start, idx_end, action);
669 /*
670 * If the rx reorder timeout is handled by host SW, see if there are
671 * remaining rx holes that require the timer to be restarted.
672 */
673 OL_RX_REORDER_TIMEOUT_UPDATE(peer, tid);
674 OL_RX_REORDER_TIMEOUT_MUTEX_UNLOCK(pdev);
675 }
676
677 void
ol_rx_pn_ind_handler(ol_txrx_pdev_handle pdev,uint16_t peer_id,uint8_t tid,uint16_t seq_num_start,uint16_t seq_num_end,uint8_t pn_ie_cnt,uint8_t * pn_ie)678 ol_rx_pn_ind_handler(ol_txrx_pdev_handle pdev,
679 uint16_t peer_id,
680 uint8_t tid,
681 uint16_t seq_num_start,
682 uint16_t seq_num_end, uint8_t pn_ie_cnt, uint8_t *pn_ie)
683 {
684 struct ol_txrx_vdev_t *vdev = NULL;
685 void *rx_desc;
686 struct ol_txrx_peer_t *peer;
687 struct ol_rx_reorder_array_elem_t *rx_reorder_array_elem;
688 unsigned int win_sz_mask;
689 qdf_nbuf_t head_msdu = NULL;
690 qdf_nbuf_t tail_msdu = NULL;
691 htt_pdev_handle htt_pdev = pdev->htt_pdev;
692 uint16_t seq_num;
693 int i = 0;
694
695 if (tid >= OL_TXRX_NUM_EXT_TIDS) {
696 ol_txrx_err("Invalid tid: %u", tid);
697 WARN_ON(1);
698 return;
699 }
700 peer = ol_txrx_peer_find_by_id(pdev, peer_id);
701
702 if (!peer) {
703 /*
704 * If we can't find a peer send this packet to OCB interface
705 * using OCB self peer
706 */
707 if (!ol_txrx_get_ocb_peer(pdev, &peer))
708 peer = NULL;
709 }
710
711 if (peer)
712 vdev = peer->vdev;
713 else
714 return;
715
716 qdf_atomic_set(&peer->fw_pn_check, 1);
717 /*TODO: Fragmentation case */
718 win_sz_mask = peer->tids_rx_reorder[tid].win_sz_mask;
719 seq_num_start &= win_sz_mask;
720 seq_num_end &= win_sz_mask;
721 seq_num = seq_num_start;
722
723 do {
724 rx_reorder_array_elem =
725 &peer->tids_rx_reorder[tid].array[seq_num];
726
727 if (rx_reorder_array_elem->head) {
728 if (pn_ie_cnt && seq_num == (int)(pn_ie[i])) {
729 qdf_nbuf_t msdu, next_msdu, mpdu_head,
730 mpdu_tail;
731 static uint32_t last_pncheck_print_time;
732 /* Do not need to initialize as C does it */
733
734 uint32_t current_time_ms;
735 union htt_rx_pn_t pn = { 0 };
736 int index, pn_len;
737
738 mpdu_head = msdu = rx_reorder_array_elem->head;
739 mpdu_tail = rx_reorder_array_elem->tail;
740
741 pn_ie_cnt--;
742 i++;
743 rx_desc = htt_rx_msdu_desc_retrieve(htt_pdev,
744 msdu);
745 index = htt_rx_msdu_is_wlan_mcast(
746 pdev->htt_pdev, rx_desc)
747 ? txrx_sec_mcast
748 : txrx_sec_ucast;
749 pn_len = pdev->rx_pn[peer->security[index].
750 sec_type].len;
751 htt_rx_mpdu_desc_pn(htt_pdev, rx_desc, &pn,
752 pn_len);
753
754 current_time_ms = qdf_system_ticks_to_msecs(
755 qdf_system_ticks());
756 if (TXRX_PN_CHECK_FAILURE_PRINT_PERIOD_MS <
757 (current_time_ms -
758 last_pncheck_print_time)) {
759 last_pncheck_print_time =
760 current_time_ms;
761 ol_txrx_warn(
762 "Tgt PN check failed - TID %d, peer %pK "
763 "("QDF_MAC_ADDR_FMT")\n"
764 " PN (u64 x2)= 0x%08llx %08llx (LSBs = %lld)\n"
765 " new seq num = %d\n",
766 tid, peer,
767 QDF_MAC_ADDR_REF(peer->mac_addr.raw),
768 pn.pn128[1],
769 pn.pn128[0],
770 pn.pn128[0] & 0xffffffffffffULL,
771 htt_rx_mpdu_desc_seq_num(htt_pdev,
772 rx_desc,
773 false));
774 } else {
775 ol_txrx_dbg(
776 "Tgt PN check failed - TID %d, peer %pK "
777 "("QDF_MAC_ADDR_FMT")\n"
778 " PN (u64 x2)= 0x%08llx %08llx (LSBs = %lld)\n"
779 " new seq num = %d\n",
780 tid, peer,
781 QDF_MAC_ADDR_REF(peer->mac_addr.raw),
782 pn.pn128[1],
783 pn.pn128[0],
784 pn.pn128[0] & 0xffffffffffffULL,
785 htt_rx_mpdu_desc_seq_num(htt_pdev,
786 rx_desc,
787 false));
788 }
789 ol_rx_err(pdev->ctrl_pdev, vdev->vdev_id,
790 peer->mac_addr.raw, tid,
791 htt_rx_mpdu_desc_tsf32(htt_pdev,
792 rx_desc),
793 OL_RX_ERR_PN, mpdu_head, NULL, 0);
794
795 /* free all MSDUs within this MPDU */
796 do {
797 next_msdu = qdf_nbuf_next(msdu);
798 htt_rx_desc_frame_free(htt_pdev, msdu);
799 if (msdu == mpdu_tail)
800 break;
801 msdu = next_msdu;
802 } while (1);
803
804 } else {
805 if (!head_msdu) {
806 head_msdu = rx_reorder_array_elem->head;
807 tail_msdu = rx_reorder_array_elem->tail;
808 } else {
809 qdf_nbuf_set_next(
810 tail_msdu,
811 rx_reorder_array_elem->head);
812 tail_msdu = rx_reorder_array_elem->tail;
813 }
814 }
815 rx_reorder_array_elem->head = NULL;
816 rx_reorder_array_elem->tail = NULL;
817 }
818 seq_num = (seq_num + 1) & win_sz_mask;
819 } while (seq_num != seq_num_end);
820
821 if (head_msdu) {
822 /* rx_opt_proc takes a NULL-terminated list of msdu netbufs */
823 qdf_nbuf_set_next(tail_msdu, NULL);
824 peer->rx_opt_proc(vdev, peer, tid, head_msdu);
825 }
826 }
827
828 #if defined(ENABLE_RX_REORDER_TRACE)
829
ol_rx_reorder_trace_attach(ol_txrx_pdev_handle pdev)830 A_STATUS ol_rx_reorder_trace_attach(ol_txrx_pdev_handle pdev)
831 {
832 int num_elems;
833
834 num_elems = 1 << TXRX_RX_REORDER_TRACE_SIZE_LOG2;
835 pdev->rx_reorder_trace.idx = 0;
836 pdev->rx_reorder_trace.cnt = 0;
837 pdev->rx_reorder_trace.mask = num_elems - 1;
838 pdev->rx_reorder_trace.data = qdf_mem_malloc(
839 sizeof(*pdev->rx_reorder_trace.data) * num_elems);
840 if (!pdev->rx_reorder_trace.data)
841 return A_NO_MEMORY;
842
843 while (--num_elems >= 0)
844 pdev->rx_reorder_trace.data[num_elems].seq_num = 0xffff;
845
846 return A_OK;
847 }
848
ol_rx_reorder_trace_detach(ol_txrx_pdev_handle pdev)849 void ol_rx_reorder_trace_detach(ol_txrx_pdev_handle pdev)
850 {
851 qdf_mem_free(pdev->rx_reorder_trace.data);
852 }
853
854 void
ol_rx_reorder_trace_add(ol_txrx_pdev_handle pdev,uint8_t tid,uint16_t reorder_idx,uint16_t seq_num,int num_mpdus)855 ol_rx_reorder_trace_add(ol_txrx_pdev_handle pdev,
856 uint8_t tid,
857 uint16_t reorder_idx, uint16_t seq_num, int num_mpdus)
858 {
859 uint32_t idx = pdev->rx_reorder_trace.idx;
860
861 pdev->rx_reorder_trace.data[idx].tid = tid;
862 pdev->rx_reorder_trace.data[idx].reorder_idx = reorder_idx;
863 pdev->rx_reorder_trace.data[idx].seq_num = seq_num;
864 pdev->rx_reorder_trace.data[idx].num_mpdus = num_mpdus;
865 pdev->rx_reorder_trace.cnt++;
866 idx++;
867 pdev->rx_reorder_trace.idx = idx & pdev->rx_reorder_trace.mask;
868 }
869
870 void
ol_rx_reorder_trace_display(ol_txrx_pdev_handle pdev,int just_once,int limit)871 ol_rx_reorder_trace_display(ol_txrx_pdev_handle pdev, int just_once, int limit)
872 {
873 static int print_count;
874 uint32_t i, start, end;
875 uint64_t cnt;
876 int elems;
877
878 if (print_count != 0 && just_once)
879 return;
880
881 print_count++;
882
883 end = pdev->rx_reorder_trace.idx;
884 if (pdev->rx_reorder_trace.data[end].seq_num == 0xffff) {
885 /* trace log has not yet wrapped around - start at the top */
886 start = 0;
887 cnt = 0;
888 } else {
889 start = end;
890 cnt = pdev->rx_reorder_trace.cnt -
891 (pdev->rx_reorder_trace.mask + 1);
892 }
893 elems = (end - 1 - start) & pdev->rx_reorder_trace.mask;
894 if (limit > 0 && elems > limit) {
895 int delta;
896
897 delta = elems - limit;
898 start += delta;
899 start &= pdev->rx_reorder_trace.mask;
900 cnt += delta;
901 }
902
903 i = start;
904 QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO,
905 " log array seq");
906 QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO,
907 " count idx tid idx num (LSBs)");
908 do {
909 uint16_t seq_num, reorder_idx;
910
911 seq_num = pdev->rx_reorder_trace.data[i].seq_num;
912 reorder_idx = pdev->rx_reorder_trace.data[i].reorder_idx;
913 if (seq_num < (1 << 14)) {
914 QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO,
915 " %6lld %4d %3d %4d %4d (%d)",
916 cnt, i, pdev->rx_reorder_trace.data[i].tid,
917 reorder_idx, seq_num, seq_num & 63);
918 } else {
919 int err = TXRX_SEQ_NUM_ERR(seq_num);
920
921 QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO,
922 " %6lld %4d err %d (%d MPDUs)",
923 cnt, i, err,
924 pdev->rx_reorder_trace.data[i].num_mpdus);
925 }
926 cnt++;
927 i++;
928 i &= pdev->rx_reorder_trace.mask;
929 } while (i != end);
930 }
931
932 #endif /* ENABLE_RX_REORDER_TRACE */
933