ASoC: Fix Blackfin I2S _pointer() implementation return in bounds values
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / drivers / staging / ath6kl / reorder / rcv_aggr.c
blob094b227b32c490f8255d042ffcef50baea34c161
1 /*
3 * Copyright (c) 2010 Atheros Communications Inc.
4 * All rights reserved.
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.
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.
24 #ifdef ATH_AR6K_11N_SUPPORT
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"
36 extern int
37 wmi_dot3_2_dix(void *osbuf);
39 static void
40 aggr_slice_amsdu(struct aggr_info *p_aggr, struct rxtid *rxtid, void **osbuf);
42 static void
43 aggr_timeout(A_ATH_TIMER arg);
45 static void
46 aggr_deque_frms(struct aggr_info *p_aggr, u8 tid, u16 seq_no, u8 order);
48 static void
49 aggr_dispatch_frames(struct aggr_info *p_aggr, A_NETBUF_QUEUE_T *q);
51 static void *
52 aggr_get_osbuf(struct aggr_info *p_aggr);
54 void *
55 aggr_init(ALLOC_NETBUFS netbuf_allocator)
57 struct aggr_info *p_aggr = NULL;
58 struct rxtid *rxtid;
59 u8 i;
60 int status = 0;
62 A_PRINTF("In aggr_init..\n");
64 do {
65 p_aggr = A_MALLOC(sizeof(struct aggr_info));
66 if(!p_aggr) {
67 A_PRINTF("Failed to allocate memory for aggr_node\n");
68 status = A_ERROR;
69 break;
72 /* Init timer and data structures */
73 A_MEMZERO(p_aggr, sizeof(struct 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);
79 p_aggr->netbuf_allocator = netbuf_allocator;
80 p_aggr->netbuf_allocator(&p_aggr->freeQ, AGGR_NUM_OF_FREE_NETBUFS);
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);
90 }while(false);
92 A_PRINTF("going out of aggr_init..status %s\n",
93 (status == 0) ? "OK":"Error");
95 if (status) {
96 /* Cleanup */
97 aggr_module_destroy(p_aggr);
99 return ((status == 0) ? p_aggr : NULL);
102 /* utility function to clear rx hold_q for a tid */
103 static void
104 aggr_delete_tid_state(struct aggr_info *p_aggr, u8 tid)
106 struct rxtid *rxtid;
107 struct rxtid_stats *stats;
109 A_ASSERT(tid < NUM_OF_TIDS && p_aggr);
111 rxtid = AGGR_GET_RXTID(p_aggr, tid);
112 stats = AGGR_GET_RXTID_STATS(p_aggr, tid);
114 if(rxtid->aggr) {
115 aggr_deque_frms(p_aggr, tid, 0, ALL_SEQNO);
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;
125 if(rxtid->hold_q) {
126 A_FREE(rxtid->hold_q);
127 rxtid->hold_q = NULL;
130 A_MEMZERO(stats, sizeof(struct rxtid_stats));
133 void
134 aggr_module_destroy(void *cntxt)
136 struct aggr_info *p_aggr = (struct aggr_info *)cntxt;
137 struct rxtid *rxtid;
138 u8 i, k;
139 A_PRINTF("%s(): aggr = %p\n",_A_FUNCNAME_, p_aggr);
140 A_ASSERT(p_aggr);
142 if(p_aggr) {
143 if(p_aggr->timerScheduled) {
144 A_UNTIMEOUT(&p_aggr->timer);
145 p_aggr->timerScheduled = false;
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);
157 A_FREE(rxtid->hold_q);
159 /* Free the dispatch q contents*/
160 while(A_NETBUF_QUEUE_SIZE(&rxtid->q)) {
161 A_NETBUF_FREE(A_NETBUF_DEQUEUE(&rxtid->q));
163 if (A_IS_MUTEX_VALID(&rxtid->lock)) {
164 A_MUTEX_DELETE(&rxtid->lock);
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));
171 A_FREE(p_aggr);
173 A_PRINTF("out aggr_module_destroy\n");
177 void
178 aggr_register_rx_dispatcher(void *cntxt, void * dev, RX_CALLBACK fn)
180 struct aggr_info *p_aggr = (struct aggr_info *)cntxt;
182 A_ASSERT(p_aggr && fn && dev);
184 p_aggr->rx_fn = fn;
185 p_aggr->dev = dev;
189 void
190 aggr_process_bar(void *cntxt, u8 tid, u16 seq_no)
192 struct aggr_info *p_aggr = (struct aggr_info *)cntxt;
193 struct rxtid_stats *stats;
195 A_ASSERT(p_aggr);
196 stats = AGGR_GET_RXTID_STATS(p_aggr, tid);
197 stats->num_bar++;
199 aggr_deque_frms(p_aggr, tid, seq_no, ALL_SEQNO);
203 void
204 aggr_recv_addba_req_evt(void *cntxt, u8 tid, u16 seq_no, u8 win_sz)
206 struct aggr_info *p_aggr = (struct aggr_info *)cntxt;
207 struct rxtid *rxtid;
208 struct rxtid_stats *stats;
210 A_ASSERT(p_aggr);
211 rxtid = AGGR_GET_RXTID(p_aggr, tid);
212 stats = AGGR_GET_RXTID_STATS(p_aggr, tid);
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);
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
223 aggr_delete_tid_state(p_aggr, tid);
226 rxtid->seq_next = seq_no;
227 /* create these queues, only upon receiving of ADDBA for a
228 * tid, reducing memory requirement
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);
235 A_MEMZERO(rxtid->hold_q, HOLD_Q_SZ(win_sz));
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
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
247 if(A_NETBUF_QUEUE_SIZE(&rxtid->q) != 0) {
248 A_PRINTF("ERROR: Frames still on queue ?\n");
249 A_ASSERT(0);
252 rxtid->aggr = true;
255 void
256 aggr_recv_delba_req_evt(void *cntxt, u8 tid)
258 struct aggr_info *p_aggr = (struct aggr_info *)cntxt;
259 struct rxtid *rxtid;
261 A_ASSERT(p_aggr);
262 A_PRINTF("%s(): tid %d\n", _A_FUNCNAME_, tid);
264 rxtid = AGGR_GET_RXTID(p_aggr, tid);
266 if(rxtid->aggr) {
267 aggr_delete_tid_state(p_aggr, tid);
271 static void
272 aggr_deque_frms(struct aggr_info *p_aggr, u8 tid, u16 seq_no, u8 order)
274 struct rxtid *rxtid;
275 struct osbuf_hold_q *node;
276 u16 idx, idx_end, seq_end;
277 struct rxtid_stats *stats;
279 A_ASSERT(p_aggr);
280 rxtid = AGGR_GET_RXTID(p_aggr, tid);
281 stats = AGGR_GET_RXTID_STATS(p_aggr, tid);
283 /* idx is absolute location for first frame */
284 idx = AGGR_WIN_IDX(rxtid->seq_next, rxtid->hold_q_sz);
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.
298 seq_end = (seq_no) ? seq_no : rxtid->seq_next;
299 idx_end = AGGR_WIN_IDX(seq_end, rxtid->hold_q_sz);
301 /* Critical section begins */
302 A_MUTEX_LOCK(&rxtid->lock);
303 do {
305 node = &rxtid->hold_q[idx];
307 if((order == CONTIGUOUS_SEQNO) && (!node->osbuf))
308 break;
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
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);
320 node->osbuf = NULL;
321 } else {
322 stats->num_hole++;
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);
332 stats->num_delivered += A_NETBUF_QUEUE_SIZE(&rxtid->q);
333 aggr_dispatch_frames(p_aggr, &rxtid->q);
336 static void *
337 aggr_get_osbuf(struct aggr_info *p_aggr)
339 void *buf = NULL;
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
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);
350 if (A_NETBUF_QUEUE_SIZE(&p_aggr->freeQ)) {
351 buf = A_NETBUF_DEQUEUE(&p_aggr->freeQ);
354 return buf;
358 static void
359 aggr_slice_amsdu(struct aggr_info *p_aggr, struct rxtid *rxtid, void **osbuf)
361 void *new_buf;
362 u16 frame_8023_len, payload_8023_len, mac_hdr_len, amsdu_len;
363 u8 *framep;
365 /* Frame format at this point:
366 * [DIX hdr | 802.3 | 802.3 | ... | 802.3]
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.
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;
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;
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;
400 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) != 0) {
403 A_PRINTF("dot3_2_dix err..\n");
404 A_NETBUF_FREE(new_buf);
405 break;
408 A_NETBUF_ENQUEUE(&rxtid->q, new_buf);
410 /* Is this the last subframe within this aggregate ? */
411 if ((amsdu_len - frame_8023_len) == 0) {
412 break;
415 /* Add the length of A-MSDU subframe padding bytes -
416 * Round to nearest word.
418 frame_8023_len = ((frame_8023_len + 3) & ~3);
420 framep += frame_8023_len;
421 amsdu_len -= frame_8023_len;
424 A_NETBUF_FREE(*osbuf);
425 *osbuf = NULL;
428 void
429 aggr_process_recv_frm(void *cntxt, u8 tid, u16 seq_no, bool is_amsdu, void **osbuf)
431 struct aggr_info *p_aggr = (struct aggr_info *)cntxt;
432 struct rxtid *rxtid;
433 struct rxtid_stats *stats;
434 u16 idx, st, cur, end;
435 u16 *log_idx;
436 struct osbuf_hold_q *node;
437 PACKET_LOG *log;
439 A_ASSERT(p_aggr);
440 A_ASSERT(tid < NUM_OF_TIDS);
442 rxtid = AGGR_GET_RXTID(p_aggr, tid);
443 stats = AGGR_GET_RXTID_STATS(p_aggr, tid);
445 stats->num_into_aggr++;
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);
453 return;
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);
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.
475 u16 extended_end;
477 extended_end = (end + rxtid->hold_q_sz-1) & IEEE80211_MAX_SEQ_NO;
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);
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);
497 aggr_deque_frms(p_aggr, tid, st, ALL_SEQNO);
500 stats->num_oow++;
503 idx = AGGR_WIN_IDX(seq_no, rxtid->hold_q_sz);
505 /*enque the frame, in hold_q */
506 node = &rxtid->hold_q[idx];
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.
521 A_NETBUF_FREE(node->osbuf);
522 stats->num_dups++;
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++;
533 A_MUTEX_UNLOCK(&rxtid->lock);
535 *osbuf = NULL;
536 aggr_deque_frms(p_aggr, tid, 0, CONTIGUOUS_SEQNO);
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;
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.
561 void
562 aggr_reset_state(void *cntxt)
564 u8 tid;
565 struct aggr_info *p_aggr = (struct aggr_info *)cntxt;
567 A_ASSERT(p_aggr);
569 for(tid=0 ; tid<NUM_OF_TIDS ; tid++) {
570 aggr_delete_tid_state(p_aggr, tid);
575 static void
576 aggr_timeout(A_ATH_TIMER arg)
578 u8 i,j;
579 struct aggr_info *p_aggr = (struct aggr_info *)arg;
580 struct rxtid *rxtid;
581 struct rxtid_stats *stats;
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.
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);
591 if(rxtid->aggr == false ||
592 rxtid->timerMon == false ||
593 rxtid->progress == true) {
594 continue;
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);
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);
607 if(rxtid->aggr == true && rxtid->hold_q) {
608 for(j = 0 ; j < rxtid->hold_q_sz ; j++)
610 if(rxtid->hold_q[j].osbuf)
612 p_aggr->timerScheduled = true;
613 rxtid->timerMon = true;
614 rxtid->progress = false;
615 break;
619 if(j >= rxtid->hold_q_sz) {
620 rxtid->timerMon = false;
625 if(p_aggr->timerScheduled) {
626 /* Rearm the timer*/
627 A_TIMEOUT_MS(&p_aggr->timer, AGGR_RX_TIMEOUT, 0);
632 static void
633 aggr_dispatch_frames(struct aggr_info *p_aggr, A_NETBUF_QUEUE_T *q)
635 void *osbuf;
637 while((osbuf = A_NETBUF_DEQUEUE(q))) {
638 p_aggr->rx_fn(p_aggr->dev, osbuf);
642 void
643 aggr_dump_stats(void *cntxt, PACKET_LOG **log_buf)
645 struct aggr_info *p_aggr = (struct aggr_info *)cntxt;
646 struct rxtid *rxtid;
647 struct rxtid_stats *stats;
648 u8 i;
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);
662 A_PRINTF("================================================\n\n");
666 #endif /* ATH_AR6K_11N_SUPPORT */