00001
00013
00014
00015
00016
00017
00018 #include "bam.h"
00019 #include "bam_task.h"
00020 #include "mac_frame.h"
00021 #include "me_mgmtframe.h"
00022 #include "mm_task.h"
00023 #include "ke_timer.h"
00024 #include "sta_mgmt.h"
00025 #include "vif_mgmt.h"
00026 #include "txu_cntrl.h"
00027 #include "txl_cfm.h"
00028 #include "ps.h"
00029 #if NX_MFP
00030 #include "mfp.h"
00031 #endif
00032 #include "tpc.h"
00038
00039
00040
00041
00043 static struct bam_baw bam_baws[NX_MAX_BA_TX];
00044
00046 struct bam_env_tag bam_env[BAM_IDX_MAX];
00047
00048
00049
00050
00051
00052 #if NX_AMPDU_TX
00053 #ifdef CFG_RWTL
00055 uint16_t tl_tudiff;
00056 #endif
00057
00066 static uint16_t bam_time_get(void)
00067 {
00068
00069 return((hal_machw_time() >> 10) & 0xFFFF);
00070 }
00071
00082 static bool bam_time_cmp(uint16_t time1, uint16_t time2)
00083 {
00084 uint16_t diff = time1 - time2;
00085
00086 #ifdef CFG_RWTL
00088 tl_tudiff = diff;
00089 #endif
00090
00091 return (((int16_t)diff) < 0);
00092 }
00093
00103 static bool bam_time_past(uint32_t time)
00104 {
00105 return (bam_time_cmp(time, bam_time_get()));
00106 }
00107
00108
00120 static unsigned int bam_baw_index_compute(struct bam_baw *baw, unsigned int offset)
00121 {
00122 return ((baw->fsn_idx + offset) % baw->buf_size);
00123 }
00124
00136 static unsigned int bam_baw_index_compute_opt(struct bam_baw *baw, unsigned int offset)
00137 {
00138 return ((baw->fsn_idx + offset) & baw->mask);
00139 }
00140
00153 static int8_t bam_move_baw(struct bam_baw *baw)
00154 {
00155 int8_t credits = 0;
00156
00157 while (baw->states[baw->fsn_idx] == BAW_CONFIRMED) {
00158 baw->states[baw->fsn_idx] = BAW_FREE;
00159 baw->fsn = (baw->fsn + 1) & ((1 << 12) - 1);
00160 baw->fsn_idx = baw->idx_compute(baw, 1);
00161 credits++;
00162 }
00163
00164 return(credits);
00165 }
00166
00176 static void bam_set_baw_state(struct bam_baw *baw, uint16_t sn, uint8_t state)
00177 {
00178 uint16_t baw_offset;
00179 int index;
00180
00181 baw_offset = ((uint16_t)(sn - baw->fsn)) & ((1 << 12) - 1);
00182
00183 ASSERT_ERR(baw_offset < baw->buf_size);
00184
00185 index = baw->idx_compute(baw, baw_offset);
00186
00187 baw->states[index] = state;
00188 }
00189
00204 static int8_t bam_check_tx_baw(struct txdesc *txdesc, uint8_t bam_idx,
00205 bool success)
00206 {
00207 struct bam_baw *baw = bam_env[bam_idx].baw;
00208 struct tx_cfm_tag *cfm = txl_cfm_tag_get(txdesc);
00209 struct hostdesc *host = &txdesc->host;
00210
00211 do
00212 {
00213
00214 if ((!(txdesc->umac.flags & AMPDU_BIT))
00215 #if NX_AMSDU_TX
00216 && (!is_mpdu_split(txdesc))
00217 #endif
00218 )
00219 break;
00220
00221
00222 if (!success && !bam_time_past(host->timestamp))
00223 {
00224
00225 cfm->status |= TX_STATUS_RETRY_REQUIRED;
00226 #if !NX_FULLY_HOSTED
00227 cfm->pn[0] = host->pn[0];
00228 cfm->pn[1] = host->pn[1];
00229 cfm->pn[2] = host->pn[2];
00230 cfm->pn[3] = host->pn[3];
00231 cfm->sn = host->sn;
00232 cfm->timestamp = host->timestamp;
00233 #endif
00234 return 0;
00235 }
00236 } while (0);
00237
00238
00239 bam_set_baw_state(baw, host->sn, BAW_CONFIRMED);
00240
00241
00242 return (bam_move_baw(baw));
00243 }
00244
00258 static uint8_t bam_create_ba_agg(uint8_t sta_idx, uint8_t tid, uint16_t ssn)
00259 {
00260 uint8_t bam_idx = bam_alloc_new_task(true);
00261
00262 if (bam_idx == BAM_INVALID_TASK_IDX)
00263 return CO_FULL;
00264
00265 TRACE_LMAC(BA, "{BAM-%d} Start TX agreement with {STA-%d}: tid=%d ssn=%d",
00266 bam_idx, sta_idx, tid, ssn);
00267
00268
00269 bam_env[bam_idx].sta_idx = sta_idx;
00270 bam_env[bam_idx].tid = tid;
00271 bam_env[bam_idx].dialog_token = co_rand_byte();
00272 bam_env[bam_idx].ba_timeout = BAM_INACTIVITY_TO_DURATION;
00273 bam_env[bam_idx].ba_policy = 1;
00274 bam_env[bam_idx].dev_type = BA_ORIGINATOR;
00275 bam_env[bam_idx].buffer_size = nx_txdesc_cnt[mac_tid2ac[tid]];
00276 bam_env[bam_idx].ssn = ssn;
00277 bam_env[bam_idx].pkt_cnt = 0;
00278
00279
00280 sta_info_tab[sta_idx].ba_info[tid].bam_idx_tx = bam_idx;
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290 bam_send_air_action_frame(sta_idx, &bam_env[bam_idx], MAC_BA_ACTION_DELBA, 0, 0,
00291 MAC_RS_TIMEOUT, NULL);
00292
00293
00294 bam_send_air_action_frame(sta_idx, &bam_env[bam_idx], MAC_BA_ACTION_ADDBA_REQ, 0, 0, 0, NULL);
00295
00296
00297 sta_mgmt_set_add_ba_time(sta_idx, tid, ke_time());
00298
00299
00300 ke_timer_set(BAM_ADD_BA_RSP_TIMEOUT_IND, KE_BUILD_ID(TASK_BAM, bam_idx),
00301 (BAM_RESPONSE_TO_DURATION * TU_DURATION));
00302
00303
00304 ke_state_set(KE_BUILD_ID(TASK_BAM, bam_idx), BAM_WAIT_RSP);
00305
00306 return CO_OK;
00307 }
00308 #endif
00309
00310 void bam_init(void)
00311 {
00312 for (int bam_idx = 0; bam_idx < BAM_IDX_MAX; bam_idx++)
00313 {
00314 bam_env[bam_idx].sta_idx = INVALID_STA_IDX;
00315
00316
00317 if (bam_idx >= BAM_FIRST_TX_IDX)
00318 {
00319 bam_env[bam_idx].baw = &bam_baws[bam_idx - BAM_FIRST_TX_IDX];
00320 }
00321
00322
00323 ke_state_set(KE_BUILD_ID(TASK_BAM, bam_idx), BAM_IDLE);
00324 }
00325 }
00326
00327 #if NX_AMPDU_TX || NX_REORD
00328 void bam_param_sta_info_tab_reset(uint16_t bam_idx)
00329 {
00330 uint16_t sta_idx = bam_env[bam_idx].sta_idx;
00331 uint8_t tid = bam_env[bam_idx].tid;
00332
00333
00334 switch (bam_env[bam_idx].dev_type)
00335 {
00336 case BA_RESPONDER:
00337 {
00338 sta_info_tab[sta_idx].ba_info[tid].bam_idx_rx = BAM_INVALID_TASK_IDX;
00339 } break;
00340
00341 case BA_ORIGINATOR:
00342 {
00343 sta_info_tab[sta_idx].ba_info[tid].bam_idx_tx = BAM_INVALID_TASK_IDX;
00344 } break;
00345
00346 default:
00347 {
00348
00349 } break;
00350 }
00351 }
00352
00353 uint16_t bam_alloc_new_task(bool tx)
00354 {
00355 uint8_t start, cnt;
00356
00357
00358 if (tx)
00359 {
00360 start = BAM_FIRST_TX_IDX;
00361 cnt = BAM_NB_TX_IDX;
00362 }
00363 else
00364 {
00365 start = BAM_FIRST_RX_IDX;
00366 cnt = BAM_NB_RX_IDX;
00367 }
00368
00369
00370 for (int i = start; i < (start + cnt); i++)
00371 {
00372
00373 if (bam_state[i] == BAM_IDLE)
00374 {
00375
00376 return i;
00377 }
00378 }
00379
00380 TRACE_LMAC(BA, "No more BA (TX=%d) task available", tx);
00381 return BAM_INVALID_TASK_IDX;
00382 }
00383
00384 void bam_delete_ba_agg(uint8_t bam_idx)
00385 {
00386
00387 ke_task_id_t task_id = KE_BUILD_ID(TASK_BAM, bam_idx);
00388
00389 TRACE_LMAC(BA, "{BAM-%d} agreement deleted", bam_idx);
00390
00391
00392 ke_timer_clear(BAM_ADD_BA_RSP_TIMEOUT_IND, task_id);
00393
00394 ke_timer_clear(BAM_INACTIVITY_TIMEOUT_IND, task_id);
00395
00396
00397 bam_param_sta_info_tab_reset(bam_idx);
00398
00399
00400 ke_state_set(task_id, BAM_IDLE);
00401 }
00402
00403 void bam_delete_all_ba_agg(uint8_t sta_idx)
00404 {
00405
00406 for (int i = 0; i < BAM_IDX_MAX; i++)
00407 {
00408
00409 if (bam_state[i] == BAM_IDLE)
00410 {
00411 continue;
00412 }
00413
00414
00415 if (bam_env[i].sta_idx != sta_idx)
00416 {
00417 continue;
00418 }
00419
00420
00421 ke_state_set(KE_BUILD_ID(TASK_BAM, i), BAM_DELETE);
00422
00423
00424 bam_send_mm_ba_del_req(sta_idx, i);
00425 }
00426 }
00427
00428 void bam_start_inactivity_timer(uint16_t bam_idx)
00429 {
00430 ke_timer_set(BAM_INACTIVITY_TIMEOUT_IND, KE_BUILD_ID(TASK_BAM, bam_idx),
00431 bam_env[bam_idx].ba_timeout * TU_DURATION);
00432 }
00433
00434 void bam_send_mm_ba_add_req(uint16_t sta_idx, uint16_t bam_idx)
00435 {
00436
00437 struct mm_ba_add_req *req = KE_MSG_ALLOC(MM_BA_ADD_REQ,
00438 TASK_MM, KE_BUILD_ID(TASK_BAM, bam_idx),
00439 mm_ba_add_req);
00440
00441
00442 req->type = (bam_env[bam_idx].dev_type == BA_ORIGINATOR) ? 0 : 1;
00443 req->sta_idx = sta_idx;
00444 req->tid = bam_env[bam_idx].tid;
00445 req->bufsz = bam_env[bam_idx].buffer_size;
00446 req->ssn = bam_env[bam_idx].ssn;
00447
00448
00449 ke_msg_send(req);
00450 }
00451
00452 void bam_send_mm_ba_del_req(uint16_t sta_idx, uint16_t bam_idx)
00453 {
00454
00455 struct mm_ba_del_req *req = KE_MSG_ALLOC(MM_BA_DEL_REQ,
00456 TASK_MM, KE_BUILD_ID(TASK_BAM, bam_idx),
00457 mm_ba_del_req);
00458
00459
00460
00461 ASSERT_ERR(ke_state_get(KE_BUILD_ID(TASK_BAM, bam_idx)) == BAM_DELETE);
00462
00463
00464 req->type = (bam_env[bam_idx].dev_type == BA_ORIGINATOR) ? 0 : 1;
00465 req->sta_idx = sta_idx;
00466 req->tid = bam_env[bam_idx].tid;
00467
00468
00469 ke_msg_send(req);
00470 }
00471 #endif
00472
00473 void bam_send_air_action_frame(uint8_t sta_idx,
00474 struct bam_env_tag *bam_env,
00475 uint8_t action,
00476 uint8_t dialog_token,
00477 uint16_t param,
00478 uint16_t status_code,
00479 void (*cfm_func)(void *, uint32_t))
00480 {
00481 struct txl_frame_desc_tag *frame;
00482 struct mac_hdr *buf;
00483 struct tx_hd *thd;
00484 uint8_t ac = AC_VO;
00485 int txtype;
00486 uint8_t vif_idx = sta_mgmt_get_vif_idx(sta_idx);
00487 struct vif_info_tag *vif = &vif_info_tab[vif_idx];
00488 uint32_t length = 0;
00489
00490
00491 txtype = vif_mgmt_get_txtype(vif);
00492 frame = txl_frame_get(txtype, NX_TXFRAME_LEN);
00493
00494 if (!frame)
00495 return;
00496
00497
00498 tpc_update_frame_tx_power(vif, frame);
00499
00500
00501 buf = txl_buffer_payload_get(&frame->txdesc);
00502
00503
00504 buf->fctl = MAC_FCTRL_ACTION;
00505
00506 buf->durid = 0;
00507
00508 MAC_ADDR_CPY(&buf->addr1, sta_mgmt_get_peer_addr(sta_idx));
00509
00510 MAC_ADDR_CPY(&buf->addr2, vif_mgmt_get_addr(vif_idx));
00511
00512 if (vif_mgmt_get_type(vif_idx) == VIF_AP)
00513 {
00514 MAC_ADDR_CPY(&buf->addr3, vif_mgmt_get_addr(vif_idx));
00515 }
00516 else
00517 {
00518
00519 MAC_ADDR_CPY(&buf->addr3, sta_mgmt_get_peer_addr(sta_idx));
00520 }
00521
00522 buf->seq = txl_get_seq_ctrl();
00523
00524
00525 frame->txdesc.host.vif_idx = vif_idx;
00526 frame->txdesc.host.staid = sta_idx;
00527
00528 length = MAC_SHORT_MAC_HDR_LEN;
00529
00530 #if NX_MFP
00531 frame->txdesc.umac.head_len = 0;
00532 frame->txdesc.umac.tail_len = 0;
00533 if (MFP_UNICAST_PROT == mfp_protect_mgmt_frame(&frame->txdesc, buf->fctl,
00534 MAC_BA_ACTION_CATEGORY))
00535 {
00536 txu_cntrl_protect_mgmt_frame(&frame->txdesc, buf, MAC_SHORT_MAC_HDR_LEN);
00537 length += frame->txdesc.umac.head_len;
00538 }
00539 #endif
00540
00541
00542 switch (action)
00543 {
00544 case MAC_BA_ACTION_ADDBA_REQ:
00545 {
00546 ac = mac_tid2ac[bam_env->tid];
00547 length += me_build_add_ba_req(CPU2HW(buf) + length, bam_env);
00548 } break;
00549
00550 case MAC_BA_ACTION_ADDBA_RSP:
00551 {
00552 length += me_build_add_ba_rsp(CPU2HW(buf) + length, bam_env,
00553 param, dialog_token, status_code);
00554 } break;
00555
00556 case MAC_BA_ACTION_DELBA:
00557 {
00558 ac = mac_tid2ac[bam_env->tid];
00559 length += me_build_del_ba(CPU2HW(buf) + length, bam_env,
00560 status_code);
00561 } break;
00562
00563 default:
00564 {
00565 ASSERT_WARN(0);
00566 } break;
00567 }
00568
00569 #if NX_MFP
00570 length += frame->txdesc.umac.tail_len;
00571 #endif
00572 thd = &frame->txdesc.lmac.hw_desc->thd;
00573 thd->dataendptr = (uint32_t)thd->datastartptr + length - 1;
00574 thd->frmlen = length + MAC_FCS_LEN;
00575
00576 if (cfm_func) {
00577 frame->cfm.cfm_func = cfm_func;
00578 frame->cfm.env = bam_env;
00579 }
00580
00581
00582 txl_frame_push(frame, ac);
00583 }
00584
00585 #if NX_AMPDU_TX
00586 void bam_check_ba_agg(struct txdesc *txdesc)
00587 {
00588
00589 uint32_t current_time = hal_machw_time();
00590 uint8_t sta_idx = txdesc->host.staid;
00591 uint8_t tid = txdesc->host.tid;
00592 uint8_t bam_idx;
00593 struct sta_info_tag *sta = &sta_info_tab[sta_idx];
00594
00595
00596 if (!STA_CAPA(sta, HT))
00597 return;
00598
00599
00600 sta_mgmt_ba_tx_cnt_inc(sta_idx, tid);
00601
00602
00603 if (sta->ctrl_port_state != PORT_OPEN)
00604 return;
00605
00606
00607 bam_idx = sta_mgmt_get_tx_bam_idx(sta_idx, tid);
00608
00609 if (bam_idx != BAM_INVALID_TASK_IDX)
00610 {
00611
00612 bam_env[bam_idx].last_activity_time = current_time;
00613
00614
00615 if (ke_state_get(KE_BUILD_ID(TASK_BAM, bam_idx)) == BAM_ACTIVE)
00616 {
00617
00618 struct bam_baw *baw = bam_env[bam_idx].baw;
00619 txdesc->umac.sn_win = baw->fsn;
00620 if (rc_check_aggregation(sta))
00621 {
00622 txdesc->umac.flags |= AMPDU_BIT;
00623 }
00624 txdesc->host.flags |= TXU_CNTRL_UNDER_BA;
00625 bam_set_baw_state(baw, txdesc->host.sn, BAW_PENDING);
00626 if (!(txdesc->host.flags & TXU_CNTRL_RETRY))
00627 txdesc->host.timestamp = bam_time_get() + me_tx_lft_get();
00628
00629
00630 bam_env[bam_idx].pkt_cnt++;
00631 }
00632 }
00633 else
00634 {
00635
00636
00637
00638
00639
00640
00641
00642
00643
00644
00645
00646
00647 uint32_t last_ba_time = sta_mgmt_get_add_ba_time(sta_idx, tid);
00648 if (!hal_machw_time_cmp(current_time, last_ba_time + BAM_ADDBA_REQ_INTERVAL) &&
00649 (sta_mgmt_ba_tx_cnt_get(sta_idx, tid) >= BAM_BA_AGG_TX_CNT_THRES) &&
00650 (sta->ps_state != PS_MODE_ON))
00651 {
00652
00653 bam_create_ba_agg(sta_idx, tid, txdesc->host.sn);
00654 }
00655 }
00656 }
00657
00658 int8_t bam_tx_cfm(struct txdesc *txdesc, bool success)
00659 {
00660 uint8_t sta_idx = txdesc->host.staid;
00661 uint8_t tid = txdesc->host.tid;
00662 uint8_t bam_idx;
00663 int8_t credits = 1;
00664 struct sta_info_tag *sta = &sta_info_tab[sta_idx];
00665
00666 do
00667 {
00668
00669 if (!STA_CAPA(sta, HT))
00670 break;
00671
00672
00673 sta_mgmt_ba_tx_cnt_dec(sta_idx, tid);
00674
00675
00676 if (!(txdesc->host.flags & TXU_CNTRL_UNDER_BA))
00677 break;
00678
00679
00680 bam_idx = sta_mgmt_get_tx_bam_idx(sta_idx, tid);
00681
00682
00683 if (bam_idx == BAM_INVALID_TASK_IDX)
00684 break;
00685
00686
00687 if (ke_state_get(KE_BUILD_ID(TASK_BAM, bam_idx)) != BAM_ACTIVE)
00688 break;
00689
00690
00691 bam_env[bam_idx].pkt_cnt--;
00692
00693
00694
00695 credits = bam_check_tx_baw(txdesc, bam_idx, success);
00696 } while (0);
00697
00698 return credits;
00699 }
00700
00701 void bam_baw_init(struct bam_env_tag *bam_env)
00702 {
00703 struct bam_baw *baw = bam_env->baw;
00704
00705
00706 memset(&baw->states, BAW_FREE, BAM_MAX_TX_WIN_SIZE * sizeof(uint8_t));
00707
00708
00709 baw->fsn = sta_mgmt_get_tx_ssn(bam_env->sta_idx, bam_env->tid);
00710 baw->fsn_idx = 0;
00711 baw->buf_size = bam_env->buffer_size;
00712
00713
00714 if (baw->buf_size & (baw->buf_size - 1))
00715 {
00716 baw->idx_compute = bam_baw_index_compute;
00717 }
00718 else
00719 {
00720 baw->mask = baw->buf_size - 1;
00721 baw->idx_compute = bam_baw_index_compute_opt;
00722 }
00723 }
00724
00725 int8_t bam_flush_baw(struct bam_baw *baw)
00726 {
00727 int8_t credits = 0;
00728 int i;
00729
00730 for (i = 0; i < baw->buf_size; i++) {
00731 if (baw->states[i] == BAW_CONFIRMED)
00732 credits++;
00733 }
00734
00735 return(credits);
00736 }
00737
00738 #endif
00739
00740 #if NX_REORD
00741 void bam_rx_active(uint8_t sta_idx, uint8_t tid)
00742 {
00743
00744 uint8_t bam_idx = sta_mgmt_get_rx_bam_idx(sta_idx, tid);
00745
00746 ASSERT_ERR(bam_idx < BAM_INVALID_TASK_IDX);
00747
00748 bam_env[bam_idx].last_activity_time = hal_machw_time();
00749 }
00750
00751 void bam_send_del_ba_agg(uint8_t sta_idx, uint8_t tid)
00752 {
00753 struct bam_env_tag bam;
00754 bam.sta_idx = sta_idx;
00755 bam.tid = tid;
00756 bam.dialog_token = 0;
00757 bam.ba_timeout = BAM_INACTIVITY_TO_DURATION;
00758 bam.ba_policy = 1;
00759 bam.dev_type = BA_RESPONDER;
00760 bam.buffer_size = 64;
00761 bam.ssn = 0;
00762 bam.pkt_cnt = 0;
00763
00764 bam_send_air_action_frame(sta_idx, &bam, MAC_BA_ACTION_DELBA,
00765 0, 0, MAC_BA_ST_INVALID_PARAMETERS, NULL);
00766 }
00767 #endif
00768