00001
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include <stddef.h>
00025 #include "txl_cntrl.h"
00026 #include "txl_cfm.h"
00027 #include "ke_event.h"
00028 #include "mac_frame.h"
00029 #include "dbg.h"
00030 #include "txl_agg.h"
00031 #include "txl_buffer.h"
00032 #include "txl_frame.h"
00033 #include "co_utils.h"
00034 #include "ps.h"
00035
00036 #if NX_AMPDU_TX
00037
00038 #include "mm.h"
00039
00040 #include "rxl_hwdesc.h"
00041 #endif
00042
00043 #include "macif.h"
00044 #if NX_UMAC_PRESENT
00045 #include "me_utils.h"
00046 #include "txu_cntrl.h"
00047 #endif
00048 #if (RW_BFMER_EN)
00049 #include "bfr.h"
00050 #endif //(RW_BFMER_EN)
00051
00052
00053
00054
00055
00056 struct txl_cfm_env_tag txl_cfm_env;
00057
00058 const uint32_t txl_cfm_evt_bit[NX_TXQ_CNT] =
00059 {
00060 #if NX_BEACONING
00061 [AC_BCN] = KE_EVT_TXCFM_BCN_BIT,
00062 #endif
00063 [AC_VO] = KE_EVT_TXCFM_AC3_BIT,
00064 [AC_VI] = KE_EVT_TXCFM_AC2_BIT,
00065 [AC_BE] = KE_EVT_TXCFM_AC1_BIT,
00066 [AC_BK] = KE_EVT_TXCFM_AC0_BIT,
00067 };
00068
00069 #if NX_AMPDU_TX
00070
00080 static uint8_t txl_ba_ac_get(struct rxdesc *rxdesc)
00081 {
00082 #if NX_MAC_HE
00083 uint8_t ac;
00084
00085 if (txl_he_tb_ongoing(&ac))
00086 {
00087 return ac;
00088 }
00089 else
00090 #endif
00091 {
00092 struct rx_dmadesc *dma_hdrdesc = rxl_dmadesc_get(rxdesc);
00093
00094 uint32_t statinfo = dma_hdrdesc->hd.statinfo;
00095
00096
00097 return (uint8_t)((statinfo & IMM_RSP_AC_MSK) >> IMM_RSP_AC_OFT);
00098 }
00099 }
00100
00114 static bool txl_decode_compressed_ba(struct rxdesc *badesc, struct tx_agg_desc *agg_desc)
00115 {
00116 uint8_t tid;
00117 struct rx_dmadesc *dma_hdrdesc = rxl_dmadesc_get(badesc);
00118 struct rx_hd *hdrdesc = &dma_hdrdesc->hd;
00119 struct rx_pbd *pd = HW2CPU(hdrdesc->first_pbd_ptr);
00120 struct ba_comp_frame *ba_payl = (struct ba_comp_frame *)HW2CPU(pd->datastartptr);
00121
00122
00123 if (hdrdesc->statinfo & RX_HD_ADDRMIS)
00124 return false;
00125
00126
00127 if (hdrdesc->frmlen != BA_COMPRESSED_LEN)
00128
00129 return false;
00130
00131
00132
00133 tid = (ba_payl->ba_cntrl & BA_PAYL_TID_BIT_MSK) >> BA_PAYL_TID_BIT_OFT;
00134
00135
00136 if (tid != agg_desc->tid)
00137
00138 return false;
00139
00140 memcpy(&agg_desc->ssc_bitmap_tab, &ba_payl->ssc_bitmap, sizeof(ba_payl->ssc_bitmap));
00141 agg_desc->ssc_bitmap = (struct ba_ssc_bitmap *)(&agg_desc->ssc_bitmap_tab);
00142
00143
00144 return true;
00145 }
00146
00159 static bool txl_is_ba_valid(struct tx_agg_desc *agg_desc, struct rxdesc *badesc)
00160 {
00161 uint16_t key_idx_hw;
00162 struct rx_dmadesc *dma_hdrdesc = rxl_dmadesc_get(badesc);
00163 struct rx_hd *hdrdesc = &dma_hdrdesc->hd;
00164 uint32_t statinfo = hdrdesc->statinfo;
00165 #if NX_MAC_HE
00166 struct rx_pbd *pd = HW2CPU(hdrdesc->first_pbd_ptr);
00167 struct ba_base *ba_payl = (struct ba_base *)HW2CPU(pd->datastartptr);
00168 uint16_t ba_type;
00169 #endif
00170
00171
00172 if (!(statinfo & KEY_IDX_VALID_BIT))
00173
00174 return false;
00175
00176
00177 key_idx_hw = (uint16_t)((statinfo & KEY_IDX_MSK) >> KEY_IDX_OFT);
00178
00179
00180 ASSERT_REC_VAL(key_idx_hw >= MM_SEC_DEFAULT_KEY_COUNT, false);
00181
00182
00183 if (MM_KEY_TO_STA(key_idx_hw) != agg_desc->sta_idx)
00184
00185 return false;
00186
00187 #if NX_MAC_HE
00188
00189 ba_type = ba_payl->ba_cntrl & BA_PAYL_TYPE_MSK;
00190
00191 if (ba_type == BA_MULTI_STA_TYPE)
00192 return txl_he_decode_m_ba(badesc, agg_desc);
00193 #endif
00194
00195
00196 return txl_decode_compressed_ba(badesc, agg_desc);
00197 }
00198
00209 static bool txl_comp_sn(uint16_t sn1, uint16_t sn2)
00210 {
00211 if (((uint16_t)((sn1 - sn2) & 0x0FFF)) < 0x07FF)
00212 return false;
00213 else
00214 return true;
00215 }
00216
00226 static uint32_t txl_ba_extract_ack(struct txdesc *txdesc, struct tx_agg_desc *agg_desc,
00227 int *agg_ok)
00228 {
00229 struct ba_ssc_bitmap *ssc_bitmap = agg_desc->ssc_bitmap;
00230 uint16_t ssn;
00231
00232 #if NX_MAC_HE
00233
00234
00235 if (ssc_bitmap == NULL)
00236 {
00237
00238 (*agg_ok)++;
00239 return (BA_FRAME_RECEIVED_BIT | FRAME_SUCCESSFUL_TX_BIT);
00240 }
00241 #endif
00242
00243
00244 ssn = ssc_bitmap->ssc >> SN_IN_SSC_BIT_OFT;
00245
00246
00247 if (txl_comp_sn(txdesc->host.sn, ssn))
00248 {
00249 return BA_FRAME_RECEIVED_BIT;
00250 }
00251
00252 uint16_t bit_pos = (txdesc->host.sn - ssn) & 0xFFF;
00253 uint8_t word_idx = bit_pos/16;
00254 uint8_t bit_in_word_pos = bit_pos % 16;
00255
00256
00257 if (word_idx > 3)
00258 {
00259 return BA_FRAME_RECEIVED_BIT;
00260 }
00261
00262 if (((ssc_bitmap->bitmap[word_idx] >> bit_in_word_pos) & 0x01) == 0x01)
00263 {
00264
00265 (*agg_ok)++;
00266 return (BA_FRAME_RECEIVED_BIT | FRAME_SUCCESSFUL_TX_BIT);
00267 }
00268 else
00269 {
00270 return BA_FRAME_RECEIVED_BIT;
00271 }
00272 }
00273 #endif
00274
00275
00276 void txl_cfm_init(void)
00277 {
00278
00279 memset(&txl_cfm_env, 0, sizeof(txl_cfm_env));
00280
00281 for (int i = 0; i < NX_TXQ_CNT; i++)
00282 {
00283 co_list_init(&txl_cfm_env.cfmlist[i]);
00284 }
00285 }
00286
00287 void txl_cfm_push(struct txdesc *txdesc, uint32_t status, uint8_t access_category)
00288 {
00289 struct tx_cfm_tag *cfm = txl_cfm_tag_get(txdesc);
00290 cfm->status = status;
00291
00292
00293 co_list_push_back(&txl_cfm_env.cfmlist[access_category], (struct co_list_hdr *)txdesc);
00294
00295 #if NX_AMPDU_TX
00296
00297 if (!is_mpdu_agg(txdesc))
00298 #endif
00299
00300 ke_evt_set(txl_cfm_evt_bit[access_category]);
00301 }
00302
00303 #if NX_AMPDU_TX
00304 void txl_ba_push(struct rxdesc *rxdesc)
00305 {
00306 uint8_t ac;
00307 struct tx_agg_desc *agg_desc;
00308
00309
00310 PROF_AGG_BA_RXED_SET();
00311
00312
00313 ac = txl_ba_ac_get(rxdesc);
00314
00315
00316 agg_desc = (struct tx_agg_desc *)co_list_pop_front(&(txl_cntrl_env.txlist[ac].aggregates));
00317
00318
00319 ASSERT_REC(agg_desc != NULL);
00320
00321
00322 agg_desc->status |= AGG_BA_RECEIVED;
00323
00324
00325 if (txl_is_ba_valid(agg_desc, rxdesc))
00326 agg_desc->status |= AGG_BA_VALID;
00327
00328
00329 PROF_AGG_BA_RXED_CLR();
00330 }
00331 #endif
00332
00333 void txl_cfm_evt(int access_category)
00334 {
00335 struct txdesc *txdesc;
00336 uint32_t evt_bit = txl_cfm_evt_bit[access_category];
00337 struct co_list *cfm_list = &txl_cfm_env.cfmlist[access_category];
00338 #if NX_AMPDU_TX
00339 #if NX_UMAC_PRESENT
00340 struct txdesc *txdesc_first = NULL;
00341 #endif
00342 int agg_txed = 0;
00343 int agg_ok = 0;
00344 #endif
00345
00346
00347 PROF_TX_CFM_EVT_SET();
00348
00349
00350 ASSERT_ERR(ke_evt_get() & evt_bit);
00351
00352
00353 ke_evt_clear(evt_bit);
00354
00355
00356 macif_tx_cfm_start(access_category);
00357
00358 while(1)
00359 {
00360
00361 txdesc = (struct txdesc *)co_list_pick(cfm_list);
00362
00363 if (txdesc != NULL)
00364 {
00365 #if NX_AMPDU_TX
00366 struct tx_cfm_tag *cfm = txl_cfm_tag_get(txdesc);
00367 struct tx_agg_desc *agg_desc = txdesc->lmac.agg_desc;
00368 #endif
00369
00370
00371 PROF_TX_AC_BG_SET(access_category);
00372
00373 #if NX_UAPSD && NX_UMAC_PRESENT
00374 ps_check_tx_trigger_sent(&txdesc->host,
00375 txl_cfm_tag_get(txdesc)->status);
00376 #endif
00377
00378 #if NX_AMPDU_TX
00379
00380 if (agg_desc)
00381 {
00382 uint8_t status = agg_desc->status;
00383
00384
00385 if (!(status & AGG_DONE))
00386 break;
00387
00388
00389 agg_txed++;
00390
00391
00392 cfm->status &= ~FRAME_SUCCESSFUL_TX_BIT;
00393
00394 if (status & AGG_BA_VALID)
00395 {
00396
00397 cfm->status |= txl_ba_extract_ack(txdesc, agg_desc, &agg_ok);
00398 }
00399
00400 #if (RW_BFMER_EN)
00401 if (bfr_is_enabled())
00402 {
00403
00404 bfr_tx_cfm(txdesc);
00405 }
00406 #endif //(RW_BFMER_EN)
00407
00408 #if NX_UMAC_PRESENT
00409
00410 txu_cntrl_cfm(txdesc);
00411
00412 if (is_mpdu_first(txdesc))
00413 txdesc_first = txdesc;
00414 #endif
00415
00416
00417 GLOBAL_INT_DISABLE();
00418
00419
00420 co_list_pop_front(cfm_list);
00421
00422 if (is_mpdu_last(txdesc))
00423 {
00424 #if NX_UMAC_PRESENT
00425 ASSERT_ERR(txdesc_first != NULL);
00426
00427 rc_cfm_ampdu(txdesc_first, agg_txed, agg_ok);
00428 txdesc_first = NULL;
00429 #endif
00430
00431
00432 agg_txed = 0;
00433 agg_ok = 0;
00434
00435
00436 txl_agg_release(agg_desc);
00437 }
00438
00439
00440 GLOBAL_INT_RESTORE();
00441
00442
00443 macif_tx_cfm_push(access_category, txdesc);
00444 }
00445
00446 else
00447 {
00448 #endif
00449
00450 GLOBAL_INT_DISABLE();
00451
00452
00453 co_list_pop_front(cfm_list);
00454
00455
00456 GLOBAL_INT_RESTORE();
00457
00458 #if (RW_BFMER_EN)
00459 if (bfr_is_enabled())
00460 {
00461
00462 bfr_tx_cfm(txdesc);
00463 }
00464 #endif //(RW_BFMER_EN)
00465
00466 #if NX_UMAC_PRESENT
00467
00468
00469 rc_cfm_singleton(txdesc);
00470
00471
00472 txu_cntrl_cfm(txdesc);
00473 #endif
00474
00475
00476 macif_tx_cfm_push(access_category, txdesc);
00477
00478 #if NX_AMPDU_TX
00479 }
00480 #endif
00481 }
00482 else
00483 {
00484
00485 break;
00486 }
00487 }
00488
00489
00490 macif_tx_cfm_done(access_category, false);
00491
00492
00493 PROF_TX_CFM_EVT_CLR();
00494 }
00495
00496 void txl_cfm_flush_desc(uint8_t access_category, struct txdesc *txdesc, uint32_t status)
00497 {
00498 struct tx_cfm_tag *cfm = txl_cfm_tag_get(txdesc);
00499
00500
00501 macif_tx_cfm_start(access_category);
00502
00503
00504 if (txdesc->lmac.agg_desc != NULL)
00505 cfm->status = status | A_MPDU_LAST;
00506 else if (!(cfm->status & DESC_DONE_TX_BIT))
00507 cfm->status = status;
00508
00509 #if NX_TX_FRAME
00510
00511 if (is_int_frame(txdesc))
00512 {
00513
00514 txl_frame_cfm(txdesc);
00515 }
00516 else
00517 #endif
00518 {
00519 #if NX_UMAC_PRESENT
00520
00521 txu_cntrl_cfm(txdesc);
00522 #endif
00523
00524 #if (RW_BFMER_EN)
00525 if (bfr_is_enabled())
00526 {
00527
00528 bfr_tx_cfm(txdesc);
00529 }
00530 #endif //(RW_BFMER_EN)
00531
00532
00533 macif_tx_cfm_push(access_category, txdesc);
00534
00535 #if !NX_FULLY_HOSTED
00536 txl_buffer_free_all(txdesc, access_category);
00537 #endif
00538 }
00539
00540
00541 #if NX_TX_FRAME
00542
00543 txl_frame_evt(0);
00544 #endif
00545
00546
00547 macif_tx_cfm_done(access_category, true);
00548 }
00549
00550
00551 void txl_cfm_flush(uint8_t access_category, struct co_list *list, uint32_t status)
00552 {
00553
00554 macif_tx_cfm_start(access_category);
00555
00556
00557 while (1)
00558 {
00559
00560 struct txdesc *txdesc = (struct txdesc *)co_list_pop_front(list);
00561 struct tx_cfm_tag *cfm;
00562
00563
00564 if (txdesc == NULL)
00565 break;
00566
00567
00568 cfm = txl_cfm_tag_get(txdesc);
00569 if (txdesc->lmac.agg_desc != NULL)
00570 cfm->status = status | A_MPDU_LAST;
00571 else if (!(cfm->status & DESC_DONE_TX_BIT))
00572 cfm->status = status;
00573
00574 #if NX_TX_FRAME
00575
00576 if (is_int_frame(txdesc))
00577 {
00578
00579 txl_frame_cfm(txdesc);
00580 }
00581 else
00582 #endif
00583 {
00584 #if NX_UMAC_PRESENT
00585
00586 txu_cntrl_cfm(txdesc);
00587 #endif
00588
00589 #if (RW_BFMER_EN)
00590 if (bfr_is_enabled())
00591 {
00592
00593 bfr_tx_cfm(txdesc);
00594 }
00595 #endif //(RW_BFMER_EN)
00596
00597
00598 macif_tx_cfm_push(access_category, txdesc);
00599
00600 #if !NX_FULLY_HOSTED
00601 txl_buffer_free_all(txdesc, access_category);
00602 #endif
00603 }
00604 }
00605
00606 #if NX_TX_FRAME
00607
00608 txl_frame_evt(0);
00609 #endif
00610
00611
00612 macif_tx_cfm_done(access_category, true);
00613 }
00614
00615
00617