Merge branch 'x86-platform-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[pandora-kernel.git] / drivers / staging / ath6kl / reorder / rcv_aggr.c
1 /*
2  *
3  * Copyright (c) 2010 Atheros Communications Inc.
4  * All rights reserved.
5  *
6  * 
7 //
8 // Permission to use, copy, modify, and/or distribute this software for any
9 // purpose with or without fee is hereby granted, provided that the above
10 // copyright notice and this permission notice appear in all copies.
11 //
12 // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13 // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14 // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15 // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16 // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 //
20 //
21  *
22  */
23
24 #ifdef  ATH_AR6K_11N_SUPPORT
25
26 #include <a_config.h>
27 #include <athdefs.h>
28 #include <a_types.h>
29 #include <a_osapi.h>
30 #include <a_debug.h>
31 #include "pkt_log.h"
32 #include "aggr_recv_api.h"
33 #include "aggr_rx_internal.h"
34 #include "wmi.h"
35
36 extern A_STATUS
37 wmi_dot3_2_dix(void *osbuf);
38
39 static void
40 aggr_slice_amsdu(AGGR_INFO *p_aggr, RXTID *rxtid, void **osbuf);
41
42 static void
43 aggr_timeout(A_ATH_TIMER arg);
44
45 static void
46 aggr_deque_frms(AGGR_INFO *p_aggr, A_UINT8 tid, A_UINT16 seq_no, A_UINT8 order);
47
48 static void
49 aggr_dispatch_frames(AGGR_INFO *p_aggr, A_NETBUF_QUEUE_T *q);
50
51 static void *
52 aggr_get_osbuf(AGGR_INFO *p_aggr);
53
54 void *
55 aggr_init(ALLOC_NETBUFS netbuf_allocator)
56 {
57     AGGR_INFO   *p_aggr = NULL;
58     RXTID *rxtid;
59     A_UINT8 i;
60     A_STATUS status = A_OK;
61
62     A_PRINTF("In aggr_init..\n");
63
64     do {
65         p_aggr = A_MALLOC(sizeof(AGGR_INFO));
66         if(!p_aggr) {
67             A_PRINTF("Failed to allocate memory for aggr_node\n");
68             status = A_ERROR;
69             break;
70         }
71
72         /* Init timer and data structures */
73         A_MEMZERO(p_aggr, sizeof(AGGR_INFO));
74         p_aggr->aggr_sz = AGGR_SZ_DEFAULT;
75         A_INIT_TIMER(&p_aggr->timer, aggr_timeout, p_aggr);
76         p_aggr->timerScheduled = FALSE;
77         A_NETBUF_QUEUE_INIT(&p_aggr->freeQ);
78
79         p_aggr->netbuf_allocator = netbuf_allocator;
80         p_aggr->netbuf_allocator(&p_aggr->freeQ, AGGR_NUM_OF_FREE_NETBUFS);
81
82         for(i = 0; i < NUM_OF_TIDS; i++) {
83             rxtid = AGGR_GET_RXTID(p_aggr, i);
84             rxtid->aggr = FALSE;
85             rxtid->progress = FALSE;
86             rxtid->timerMon = FALSE;
87             A_NETBUF_QUEUE_INIT(&rxtid->q);
88             A_MUTEX_INIT(&rxtid->lock);
89         }
90     }while(FALSE);
91
92     A_PRINTF("going out of aggr_init..status %s\n",
93                     (status == A_OK) ? "OK":"Error");
94
95     if(status != A_OK) {
96         /* Cleanup */
97         aggr_module_destroy(p_aggr);
98     }
99     return ((status == A_OK) ? p_aggr : NULL);
100 }
101
102 /* utility function to clear rx hold_q for a tid */
103 static void
104 aggr_delete_tid_state(AGGR_INFO *p_aggr, A_UINT8 tid)
105 {
106     RXTID *rxtid;
107     RXTID_STATS *stats;
108
109     A_ASSERT(tid < NUM_OF_TIDS && p_aggr);
110
111     rxtid = AGGR_GET_RXTID(p_aggr, tid);
112     stats = AGGR_GET_RXTID_STATS(p_aggr, tid);
113
114     if(rxtid->aggr) {
115         aggr_deque_frms(p_aggr, tid, 0, ALL_SEQNO);
116     }
117
118     rxtid->aggr = FALSE;
119     rxtid->progress = FALSE;
120     rxtid->timerMon = FALSE;
121     rxtid->win_sz = 0;
122     rxtid->seq_next = 0;
123     rxtid->hold_q_sz = 0;
124
125     if(rxtid->hold_q) {
126         A_FREE(rxtid->hold_q);
127         rxtid->hold_q = NULL;
128     }
129
130     A_MEMZERO(stats, sizeof(RXTID_STATS));
131 }
132
133 void
134 aggr_module_destroy(void *cntxt)
135 {
136     AGGR_INFO *p_aggr = (AGGR_INFO *)cntxt;
137     RXTID *rxtid;
138     A_UINT8 i, k;
139     A_PRINTF("%s(): aggr = %p\n",_A_FUNCNAME_, p_aggr);
140     A_ASSERT(p_aggr);
141
142     if(p_aggr) {
143         if(p_aggr->timerScheduled) {
144             A_UNTIMEOUT(&p_aggr->timer);
145             p_aggr->timerScheduled = FALSE;
146         }
147
148         for(i = 0; i < NUM_OF_TIDS; i++) {
149             rxtid = AGGR_GET_RXTID(p_aggr, i);
150             /* Free the hold q contents and hold_q*/
151             if(rxtid->hold_q) {
152                 for(k = 0; k< rxtid->hold_q_sz; k++) {
153                     if(rxtid->hold_q[k].osbuf) {
154                         A_NETBUF_FREE(rxtid->hold_q[k].osbuf);
155                     }
156                 }
157                 A_FREE(rxtid->hold_q);
158             }
159             /* Free the dispatch q contents*/
160             while(A_NETBUF_QUEUE_SIZE(&rxtid->q)) {
161                 A_NETBUF_FREE(A_NETBUF_DEQUEUE(&rxtid->q));
162             }
163             if (A_IS_MUTEX_VALID(&rxtid->lock)) {
164                 A_MUTEX_DELETE(&rxtid->lock);
165             }
166         }
167         /* free the freeQ and its contents*/
168         while(A_NETBUF_QUEUE_SIZE(&p_aggr->freeQ)) {
169             A_NETBUF_FREE(A_NETBUF_DEQUEUE(&p_aggr->freeQ));
170         }
171         A_FREE(p_aggr);
172     }
173     A_PRINTF("out aggr_module_destroy\n");
174 }
175
176
177 void
178 aggr_register_rx_dispatcher(void *cntxt, void * dev, RX_CALLBACK fn)
179 {
180     AGGR_INFO *p_aggr = (AGGR_INFO *)cntxt;
181
182     A_ASSERT(p_aggr && fn && dev);
183
184     p_aggr->rx_fn = fn;
185     p_aggr->dev = dev;
186 }
187
188
189 void
190 aggr_process_bar(void *cntxt, A_UINT8 tid, A_UINT16 seq_no)
191 {
192     AGGR_INFO *p_aggr = (AGGR_INFO *)cntxt;
193     RXTID_STATS *stats;
194
195     A_ASSERT(p_aggr);
196     stats = AGGR_GET_RXTID_STATS(p_aggr, tid);
197     stats->num_bar++;
198
199     aggr_deque_frms(p_aggr, tid, seq_no, ALL_SEQNO);
200 }
201
202
203 void
204 aggr_recv_addba_req_evt(void *cntxt, A_UINT8 tid, A_UINT16 seq_no, A_UINT8 win_sz)
205 {
206     AGGR_INFO *p_aggr = (AGGR_INFO *)cntxt;
207     RXTID *rxtid;
208     RXTID_STATS *stats;
209
210     A_ASSERT(p_aggr);
211     rxtid = AGGR_GET_RXTID(p_aggr, tid);
212     stats = AGGR_GET_RXTID_STATS(p_aggr, tid);
213
214     A_PRINTF("%s(): win_sz = %d aggr %d\n", _A_FUNCNAME_, win_sz, rxtid->aggr);
215     if(win_sz < AGGR_WIN_SZ_MIN || win_sz > AGGR_WIN_SZ_MAX) {
216         A_PRINTF("win_sz %d, tid %d\n", win_sz, tid);
217     }
218
219     if(rxtid->aggr) {
220         /* Just go and  deliver all the frames up from this
221          * queue, as if we got DELBA and re-initialize the queue
222          */
223         aggr_delete_tid_state(p_aggr, tid);
224     }
225
226     rxtid->seq_next = seq_no;
227     /* create these queues, only upon receiving of ADDBA for a
228      * tid, reducing memory requirement
229      */
230     rxtid->hold_q = A_MALLOC(HOLD_Q_SZ(win_sz));
231     if((rxtid->hold_q == NULL)) {
232         A_PRINTF("Failed to allocate memory, tid = %d\n", tid);
233         A_ASSERT(0);
234     }
235     A_MEMZERO(rxtid->hold_q, HOLD_Q_SZ(win_sz));
236
237     /* Update rxtid for the window sz */
238     rxtid->win_sz = win_sz;
239     /* hold_q_sz inicates the depth of holding q - which  is
240      * a factor of win_sz. Compute once, as it will be used often
241      */
242     rxtid->hold_q_sz = TID_WINDOW_SZ(win_sz);
243     /* There should be no frames on q - even when second ADDBA comes in.
244      * If aggr was previously ON on this tid, we would have cleaned up
245      * the q
246      */
247     if(A_NETBUF_QUEUE_SIZE(&rxtid->q) != 0) {
248         A_PRINTF("ERROR: Frames still on queue ?\n");
249         A_ASSERT(0);
250     }
251
252     rxtid->aggr = TRUE;
253 }
254
255 void
256 aggr_recv_delba_req_evt(void *cntxt, A_UINT8 tid)
257 {
258     AGGR_INFO *p_aggr = (AGGR_INFO *)cntxt;
259     RXTID *rxtid;
260
261     A_ASSERT(p_aggr);
262     A_PRINTF("%s(): tid %d\n", _A_FUNCNAME_, tid);
263
264     rxtid = AGGR_GET_RXTID(p_aggr, tid);
265
266     if(rxtid->aggr) {
267         aggr_delete_tid_state(p_aggr, tid);
268     }
269 }
270
271 static void
272 aggr_deque_frms(AGGR_INFO *p_aggr, A_UINT8 tid, A_UINT16 seq_no, A_UINT8 order)
273 {
274     RXTID *rxtid;
275     OSBUF_HOLD_Q *node;
276     A_UINT16 idx, idx_end, seq_end;
277     RXTID_STATS *stats;
278
279     A_ASSERT(p_aggr);
280     rxtid = AGGR_GET_RXTID(p_aggr, tid);
281     stats = AGGR_GET_RXTID_STATS(p_aggr, tid);
282
283     /* idx is absolute location for first frame */
284     idx = AGGR_WIN_IDX(rxtid->seq_next, rxtid->hold_q_sz);
285
286     /* idx_end is typically the last possible frame in the window,
287      * but changes to 'the' seq_no, when BAR comes. If seq_no
288      * is non-zero, we will go up to that and stop.
289      * Note: last seq no in current window will occupy the same
290      * index position as index that is just previous to start.
291      * An imp point : if win_sz is 7, for seq_no space of 4095,
292      * then, there would be holes when sequence wrap around occurs.
293      * Target should judiciously choose the win_sz, based on
294      * this condition. For 4095, (TID_WINDOW_SZ = 2 x win_sz
295      * 2, 4, 8, 16 win_sz works fine).
296      * We must deque from "idx" to "idx_end", including both.
297      */
298     seq_end = (seq_no) ? seq_no : rxtid->seq_next;
299     idx_end = AGGR_WIN_IDX(seq_end, rxtid->hold_q_sz);
300
301     /* Critical section begins */
302     A_MUTEX_LOCK(&rxtid->lock);
303     do {
304
305         node = &rxtid->hold_q[idx];
306
307         if((order == CONTIGUOUS_SEQNO) && (!node->osbuf))
308             break;
309
310         /* chain frames and deliver frames bcos:
311          *  1. either the frames are in order and window is contiguous, OR
312          *  2. we need to deque frames, irrespective of holes
313          */
314         if(node->osbuf) {
315             if(node->is_amsdu) {
316                 aggr_slice_amsdu(p_aggr, rxtid, &node->osbuf);
317             } else {
318                 A_NETBUF_ENQUEUE(&rxtid->q, node->osbuf);
319             }
320             node->osbuf = NULL;
321         } else {
322             stats->num_hole++;
323         }
324
325         /* window is moving */
326         rxtid->seq_next = IEEE80211_NEXT_SEQ_NO(rxtid->seq_next);
327         idx = AGGR_WIN_IDX(rxtid->seq_next, rxtid->hold_q_sz);
328     } while(idx != idx_end);
329     /* Critical section ends */
330     A_MUTEX_UNLOCK(&rxtid->lock);
331
332     stats->num_delivered += A_NETBUF_QUEUE_SIZE(&rxtid->q);
333     aggr_dispatch_frames(p_aggr, &rxtid->q);
334 }
335
336 static void *
337 aggr_get_osbuf(AGGR_INFO *p_aggr)
338 {
339     void *buf = NULL;
340
341     /* Starving for buffers?  get more from OS
342      *  check for low netbuffers( < 1/4 AGGR_NUM_OF_FREE_NETBUFS) :
343      *      re-allocate bufs if so
344      * allocate a free buf from freeQ
345      */
346     if (A_NETBUF_QUEUE_SIZE(&p_aggr->freeQ) < (AGGR_NUM_OF_FREE_NETBUFS >> 2)) {
347         p_aggr->netbuf_allocator(&p_aggr->freeQ, AGGR_NUM_OF_FREE_NETBUFS);
348     }
349
350     if (A_NETBUF_QUEUE_SIZE(&p_aggr->freeQ)) {
351         buf = A_NETBUF_DEQUEUE(&p_aggr->freeQ);
352     }
353
354     return buf;
355 }
356
357
358 static void
359 aggr_slice_amsdu(AGGR_INFO *p_aggr, RXTID *rxtid, void **osbuf)
360 {
361     void *new_buf;
362     A_UINT16 frame_8023_len, payload_8023_len, mac_hdr_len, amsdu_len;
363     A_UINT8 *framep;
364
365     /* Frame format at this point:
366      *  [DIX hdr | 802.3 | 802.3 | ... | 802.3]
367      *
368      * Strip the DIX header.
369      * Iterate through the osbuf and do:
370      *  grab a free netbuf from freeQ
371      *  find the start and end of a frame
372      *  copy it to netbuf(Vista can do better here)
373      *  convert all msdu's(802.3) frames to upper layer format - os routine
374      *      -for now lets convert from 802.3 to dix
375      *  enque this to dispatch q of tid
376      * repeat
377      * free the osbuf - to OS. It's been sliced.
378      */
379
380     mac_hdr_len = sizeof(ATH_MAC_HDR);
381     framep = A_NETBUF_DATA(*osbuf) + mac_hdr_len;
382     amsdu_len = A_NETBUF_LEN(*osbuf) - mac_hdr_len;
383
384     while(amsdu_len > mac_hdr_len) {
385         /* Begin of a 802.3 frame */
386         payload_8023_len = A_BE2CPU16(((ATH_MAC_HDR *)framep)->typeOrLen);
387 #define MAX_MSDU_SUBFRAME_PAYLOAD_LEN 1508
388 #define MIN_MSDU_SUBFRAME_PAYLOAD_LEN 46
389         if(payload_8023_len < MIN_MSDU_SUBFRAME_PAYLOAD_LEN || payload_8023_len > MAX_MSDU_SUBFRAME_PAYLOAD_LEN) {
390             A_PRINTF("802.3 AMSDU frame bound check failed. len %d\n", payload_8023_len);
391             break;
392         }
393         frame_8023_len = payload_8023_len + mac_hdr_len;
394         new_buf = aggr_get_osbuf(p_aggr);
395         if(new_buf == NULL) {
396             A_PRINTF("No buffer available \n");
397             break;
398         }
399
400         A_MEMCPY(A_NETBUF_DATA(new_buf), framep, frame_8023_len);
401         A_NETBUF_PUT(new_buf, frame_8023_len);
402         if (wmi_dot3_2_dix(new_buf) != A_OK) {
403             A_PRINTF("dot3_2_dix err..\n");
404             A_NETBUF_FREE(new_buf);
405             break;
406         }
407
408         A_NETBUF_ENQUEUE(&rxtid->q, new_buf);
409
410         /* Is this the last subframe within this aggregate ? */
411         if ((amsdu_len - frame_8023_len) == 0) {
412             break;
413         }
414
415         /* Add the length of A-MSDU subframe padding bytes -
416          * Round to nearest word.
417          */
418         frame_8023_len = ((frame_8023_len + 3) & ~3);
419
420         framep += frame_8023_len;
421         amsdu_len -= frame_8023_len;
422     }
423
424     A_NETBUF_FREE(*osbuf);
425     *osbuf = NULL;
426 }
427
428 void
429 aggr_process_recv_frm(void *cntxt, A_UINT8 tid, A_UINT16 seq_no, A_BOOL is_amsdu, void **osbuf)
430 {
431     AGGR_INFO *p_aggr = (AGGR_INFO *)cntxt;
432     RXTID *rxtid;
433     RXTID_STATS *stats;
434     A_UINT16 idx, st, cur, end;
435     A_UINT16 *log_idx;
436     OSBUF_HOLD_Q *node;
437     PACKET_LOG *log;
438
439     A_ASSERT(p_aggr);
440     A_ASSERT(tid < NUM_OF_TIDS);
441
442     rxtid = AGGR_GET_RXTID(p_aggr, tid);
443     stats = AGGR_GET_RXTID_STATS(p_aggr, tid);
444
445     stats->num_into_aggr++;
446
447     if(!rxtid->aggr) {
448         if(is_amsdu) {
449             aggr_slice_amsdu(p_aggr, rxtid, osbuf);
450             stats->num_amsdu++;
451             aggr_dispatch_frames(p_aggr, &rxtid->q);
452         }
453         return;
454     }
455
456     /* Check the incoming sequence no, if it's in the window */
457     st = rxtid->seq_next;
458     cur = seq_no;
459     end = (st + rxtid->hold_q_sz-1) & IEEE80211_MAX_SEQ_NO;
460     /* Log the pkt info for future analysis */
461     log = &p_aggr->pkt_log;
462     log_idx = &log->last_idx;
463     log->info[*log_idx].cur = cur;
464     log->info[*log_idx].st = st;
465     log->info[*log_idx].end = end;
466     *log_idx = IEEE80211_NEXT_SEQ_NO(*log_idx);
467
468     if(((st < end) && (cur < st || cur > end)) ||
469       ((st > end) && (cur > end) && (cur < st))) {
470         /* the cur frame is outside the window. Since we know
471          * our target would not do this without reason it must
472          * be assumed that the window has moved for some valid reason.
473          * Therefore, we dequeue all frames and start fresh.
474          */
475         A_UINT16 extended_end;
476
477         extended_end = (end + rxtid->hold_q_sz-1) & IEEE80211_MAX_SEQ_NO;
478
479         if(((end < extended_end) && (cur < end || cur > extended_end)) ||
480            ((end > extended_end) && (cur > extended_end) && (cur < end))) {
481             // dequeue all frames in queue and shift window to new frame
482             aggr_deque_frms(p_aggr, tid, 0, ALL_SEQNO);
483             //set window start so that new frame is last frame in window
484             if(cur >= rxtid->hold_q_sz-1) {
485                 rxtid->seq_next = cur - (rxtid->hold_q_sz-1);
486             }else{
487                 rxtid->seq_next = IEEE80211_MAX_SEQ_NO - (rxtid->hold_q_sz-2 - cur);
488             }
489         } else {
490             // dequeue only those frames that are outside the new shifted window
491             if(cur >= rxtid->hold_q_sz-1) {
492                 st = cur - (rxtid->hold_q_sz-1);
493             }else{
494                 st = IEEE80211_MAX_SEQ_NO - (rxtid->hold_q_sz-2 - cur);
495             }
496
497             aggr_deque_frms(p_aggr, tid, st, ALL_SEQNO);
498         }
499
500         stats->num_oow++;
501     }
502
503     idx = AGGR_WIN_IDX(seq_no, rxtid->hold_q_sz);
504
505     /*enque the frame, in hold_q */
506     node = &rxtid->hold_q[idx];
507
508     A_MUTEX_LOCK(&rxtid->lock);
509     if(node->osbuf) {
510         /* Is the cur frame duplicate or something beyond our
511          * window(hold_q -> which is 2x, already)?
512          * 1. Duplicate is easy - drop incoming frame.
513          * 2. Not falling in current sliding window.
514          *  2a. is the frame_seq_no preceding current tid_seq_no?
515          *      -> drop the frame. perhaps sender did not get our ACK.
516          *         this is taken care of above.
517          *  2b. is the frame_seq_no beyond window(st, TID_WINDOW_SZ);
518          *      -> Taken care of it above, by moving window forward.
519          *
520          */
521         A_NETBUF_FREE(node->osbuf);
522         stats->num_dups++;
523     }
524
525     node->osbuf = *osbuf;
526     node->is_amsdu = is_amsdu;
527     node->seq_no = seq_no;
528     if(node->is_amsdu) {
529         stats->num_amsdu++;
530     } else {
531         stats->num_mpdu++;
532     }
533     A_MUTEX_UNLOCK(&rxtid->lock);
534
535     *osbuf = NULL;
536     aggr_deque_frms(p_aggr, tid, 0, CONTIGUOUS_SEQNO);
537
538     if(p_aggr->timerScheduled) {
539         rxtid->progress = TRUE;
540     }else{
541         for(idx=0 ; idx<rxtid->hold_q_sz ; idx++) {
542             if(rxtid->hold_q[idx].osbuf) {
543                 /* there is a frame in the queue and no timer so
544                  * start a timer to ensure that the frame doesn't remain
545                  * stuck forever. */
546                 p_aggr->timerScheduled = TRUE;
547                 A_TIMEOUT_MS(&p_aggr->timer, AGGR_RX_TIMEOUT, 0);
548                 rxtid->progress = FALSE;
549                 rxtid->timerMon = TRUE;
550                 break;
551             }
552         }
553     }
554 }
555
556 /*
557  * aggr_reset_state -- Called when it is deemed necessary to clear the aggregate
558  *  hold Q state.  Examples include when a Connect event or disconnect event is
559  *  received.
560  */
561 void
562 aggr_reset_state(void *cntxt)
563 {
564     A_UINT8 tid;
565     AGGR_INFO *p_aggr = (AGGR_INFO *)cntxt;
566
567     A_ASSERT(p_aggr);
568
569     for(tid=0 ; tid<NUM_OF_TIDS ; tid++) {
570         aggr_delete_tid_state(p_aggr, tid);
571     }
572 }
573
574
575 static void
576 aggr_timeout(A_ATH_TIMER arg)
577 {
578     A_UINT8 i,j;
579     AGGR_INFO *p_aggr = (AGGR_INFO *)arg;
580     RXTID   *rxtid;
581     RXTID_STATS *stats;
582     /*
583      * If the q for which the timer was originally started has
584      * not progressed then it is necessary to dequeue all the
585      * contained frames so that they are not held forever.
586      */
587     for(i = 0; i < NUM_OF_TIDS; i++) {
588         rxtid = AGGR_GET_RXTID(p_aggr, i);
589         stats = AGGR_GET_RXTID_STATS(p_aggr, i);
590
591         if(rxtid->aggr == FALSE ||
592            rxtid->timerMon == FALSE ||
593            rxtid->progress == TRUE) {
594             continue;
595         }
596         // dequeue all frames in for this tid
597         stats->num_timeouts++;
598         A_PRINTF("TO: st %d end %d\n", rxtid->seq_next, ((rxtid->seq_next + rxtid->hold_q_sz-1) & IEEE80211_MAX_SEQ_NO));
599         aggr_deque_frms(p_aggr, i, 0, ALL_SEQNO);
600     }
601
602     p_aggr->timerScheduled = FALSE;
603     // determine whether a new timer should be started.
604     for(i = 0; i < NUM_OF_TIDS; i++) {
605         rxtid = AGGR_GET_RXTID(p_aggr, i);
606
607         if(rxtid->aggr == TRUE && rxtid->hold_q) {
608             for(j = 0 ; j < rxtid->hold_q_sz ; j++)
609             {
610                 if(rxtid->hold_q[j].osbuf)
611                 {
612                     p_aggr->timerScheduled = TRUE;
613                     rxtid->timerMon = TRUE;
614                     rxtid->progress = FALSE;
615                     break;
616                 }
617             }
618
619             if(j >= rxtid->hold_q_sz) {
620                 rxtid->timerMon = FALSE;
621             }
622         }
623     }
624
625     if(p_aggr->timerScheduled) {
626         /* Rearm the timer*/
627         A_TIMEOUT_MS(&p_aggr->timer, AGGR_RX_TIMEOUT, 0);
628     }
629
630 }
631
632 static void
633 aggr_dispatch_frames(AGGR_INFO *p_aggr, A_NETBUF_QUEUE_T *q)
634 {
635     void *osbuf;
636
637     while((osbuf = A_NETBUF_DEQUEUE(q))) {
638         p_aggr->rx_fn(p_aggr->dev, osbuf);
639     }
640 }
641
642 void
643 aggr_dump_stats(void *cntxt, PACKET_LOG **log_buf)
644 {
645     AGGR_INFO *p_aggr = (AGGR_INFO *)cntxt;
646     RXTID   *rxtid;
647     RXTID_STATS *stats;
648     A_UINT8 i;
649
650     *log_buf = &p_aggr->pkt_log;
651     A_PRINTF("\n\n================================================\n");
652     A_PRINTF("tid: num_into_aggr, dups, oow, mpdu, amsdu, delivered, timeouts, holes, bar, seq_next\n");
653     for(i = 0; i < NUM_OF_TIDS; i++) {
654         stats = AGGR_GET_RXTID_STATS(p_aggr, i);
655         rxtid = AGGR_GET_RXTID(p_aggr, i);
656         A_PRINTF("%d: %d %d %d %d %d %d %d %d %d : %d\n", i, stats->num_into_aggr, stats->num_dups,
657                     stats->num_oow, stats->num_mpdu,
658                     stats->num_amsdu, stats->num_delivered, stats->num_timeouts,
659                     stats->num_hole, stats->num_bar,
660                     rxtid->seq_next);
661     }
662     A_PRINTF("================================================\n\n");
663
664 }
665
666 #endif  /* ATH_AR6K_11N_SUPPORT */