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