00001
00020
00021
00022
00023
00024 #include "co_int.h"
00025 #include "co_bool.h"
00026 #include <string.h>
00027
00028 #include "dbg_assert.h"
00029 #include "mac.h"
00030 #include "mac_frame.h"
00031 #include "mm.h"
00032 #include "macif.h"
00033 #include "rxl_hwdesc.h"
00034 #include "txl_buffer.h"
00035 #if NX_TX_FRAME
00036 #include "txl_frame.h"
00037 #endif
00038 #include "tx_swdesc.h"
00039 #include "txl_cfm.h"
00040 #include "txl_cntrl.h"
00041 #include "rxl_cntrl.h"
00042 #include "reg_mac_pl.h"
00043 #include "reg_mac_core.h"
00044 #include "dbg.h"
00045 #include "ps.h"
00046 #if (NX_P2P)
00047 #include "p2p.h"
00048 #endif //(NX_P2P)
00049 #if (NX_TD)
00050 #include "td.h"
00051 #endif //(NX_TD)
00052 #if NX_UMAC_PRESENT
00053 #include "txu_cntrl.h"
00054 #include "apm.h"
00055 #endif
00056 #if NX_MFP
00057 #include "mfp.h"
00058 #endif
00059 #if (RW_BFMER_EN)
00060 #include "bfr.h"
00061 #endif //(RW_BFMER_EN)
00062 #if NX_MAC_HE
00063 #include "txl_he.h"
00064 #endif
00065 #include "txl_agg.h"
00066
00067 #if NX_AMPDU_TX
00068
00069
00070
00071
00072
00073 #if RW_MUMIMO_TX_EN
00075 #define TX_SEC_IRQ_BITS_MERGED ( NXMAC_SEC_U_3AC_3_TX_TRIGGER_BIT | \
00076 NXMAC_SEC_U_3AC_2_TX_TRIGGER_BIT | \
00077 NXMAC_SEC_U_3AC_1_TX_TRIGGER_BIT | \
00078 NXMAC_SEC_U_3AC_0_TX_TRIGGER_BIT | \
00079 NXMAC_SEC_U_2AC_3_TX_TRIGGER_BIT | \
00080 NXMAC_SEC_U_2AC_2_TX_TRIGGER_BIT | \
00081 NXMAC_SEC_U_2AC_1_TX_TRIGGER_BIT | \
00082 NXMAC_SEC_U_2AC_0_TX_TRIGGER_BIT | \
00083 NXMAC_SEC_U_1AC_3_TX_TRIGGER_BIT | \
00084 NXMAC_SEC_U_1AC_2_TX_TRIGGER_BIT | \
00085 NXMAC_SEC_U_1AC_1_TX_TRIGGER_BIT | \
00086 NXMAC_SEC_U_1AC_0_TX_TRIGGER_BIT )
00087
00089 #define MU_AMPDU_CLOSE() \
00090 { \
00091 txl_mumimo_ampdu_finish(ac, user_pos); \
00092 \
00093 if (txlist->mumimo.open & txlist->mumimo.users) \
00094 { \
00095 \
00096 \
00097 ASSERT_ERR(txlist->mumimo.txdesc[user_pos] == NULL); \
00098 txlist->mumimo.txdesc[user_pos] = txdesc; \
00099 status = MU_PAUSED; \
00100 break; \
00101 } \
00102 else \
00103 { \
00104 \
00105 txl_agg_mumimo_close(ac); \
00106 \
00107 \
00108 continue; \
00109 } \
00110 }
00111 #endif
00112
00117 const uint8_t TX_VHT_RATE_TO_MIN_SEP[10*4*2] =
00118 {
00119
00120 [ 0] = 1, [ 1] = 1, [ 2] = 2, [ 3] = 2,
00121 [ 8] = 2, [ 9] = 2, [ 10] = 4, [ 11] = 4,
00122 [ 16] = 3, [ 17] = 3, [ 18] = 6, [ 19] = 6,
00123 [ 24] = 4, [ 25] = 4, [ 26] = 7, [ 27] = 8,
00124 [ 32] = 5, [ 33] = 6, [ 34] = 11, [ 35] = 12,
00125 [ 40] = 7, [ 41] = 8, [ 42] = 14, [ 43] = 15,
00126 [ 48] = 8, [ 49] = 9, [ 50] = 16, [ 51] = 17,
00127 [ 56] = 9, [ 57] = 10, [ 58] = 17, [ 59] = 19,
00128 [ 64] = 10, [ 65] = 11, [ 66] = 21, [ 67] = 23,
00129 [ 72] = 11, [ 73] = 13, [ 74] = 23, [ 75] = 25,
00130
00131 [ 4] = 4, [ 5] = 5, [ 6] = 8, [ 7] = 9,
00132 [ 12] = 8, [ 13] = 9, [ 14] = 15, [ 15] = 17,
00133 [ 20] = 11, [ 21] = 13, [ 22] = 22, [ 23] = 25,
00134 [ 28] = 15, [ 29] = 17, [ 30] = 30, [ 31] = 33,
00135 [ 36] = 22, [ 37] = 25, [ 38] = 44, [ 39] = 49,
00136 [ 44] = 30, [ 45] = 33, [ 46] = 59, [ 47] = 65,
00137 [ 52] = 33, [ 53] = 37, [ 54] = 66, [ 55] = 74,
00138 [ 60] = 37, [ 61] = 41, [ 62] = 74, [ 63] = 82,
00139 [ 68] = 44, [ 69] = 49, [ 70] = 88, [ 71] = 98,
00140 [ 76] = 49, [ 77] = 55, [ 78] = 98, [ 79] = 109,
00141 };
00142
00143
00148 const uint16_t TX_VHT_RATE_TO_32US_LEN[10*4*2] =
00149 {
00150
00151 [ 0] = 26, [ 1] = 28, [ 2] = 54, [ 3] = 60,
00152 [ 8] = 52, [ 9] = 57, [ 10] = 108, [ 11] = 120,
00153 [ 16] = 78, [ 17] = 86, [ 18] = 162, [ 19] = 180,
00154 [ 24] = 104, [ 25] = 115, [ 26] = 216, [ 27] = 240,
00155 [ 32] = 156, [ 33] = 173, [ 34] = 324, [ 35] = 360,
00156 [ 40] = 208, [ 41] = 231, [ 42] = 432, [ 43] = 480,
00157 [ 48] = 234, [ 49] = 260, [ 50] = 486, [ 51] = 540,
00158 [ 56] = 260, [ 57] = 288, [ 58] = 540, [ 59] = 600,
00159 [ 64] = 312, [ 65] = 346, [ 66] = 648, [ 67] = 720,
00160 [ 72] = 346, [ 73] = 385, [ 74] = 720, [ 75] = 800,
00161
00162 [ 4] = 117, [ 5] = 130, [ 6] = 234, [ 7] = 260,
00163 [ 12] = 234, [ 13] = 260, [ 14] = 468, [ 15] = 520,
00164 [ 20] = 351, [ 21] = 390, [ 22] = 702, [ 23] = 780,
00165 [ 28] = 468, [ 29] = 520, [ 30] = 936, [ 31] = 1040,
00166 [ 36] = 702, [ 37] = 780, [ 38] = 1404, [ 39] = 1560,
00167 [ 44] = 936, [ 45] = 1040, [ 46] = 1872, [ 47] = 2080,
00168 [ 52] = 1053, [ 53] = 1170, [ 54] = 2106, [ 55] = 2340,
00169 [ 60] = 1170, [ 61] = 1300, [ 62] = 2340, [ 63] = 2600,
00170 [ 68] = 1404, [ 69] = 1560, [ 70] = 2808, [ 71] = 3120,
00171 [ 76] = 1560, [ 77] = 1733, [ 78] = 3120, [ 79] = 3466,
00172 };
00173
00174 #if RW_MUMIMO_TX_EN
00176 #define VHT_BW 4
00178 #define VHT_MCS 10
00179
00183 const uint16_t VHT_NDBPS[VHT_BW][VHT_MCS] = {
00184
00185 [BW_20MHZ] = {26, 52, 78, 104, 156, 208, 234, 260, 312, 1040},
00186 [BW_40MHZ] = {54, 108, 162, 216, 324, 432, 486, 540, 648, 720 },
00187 [BW_80MHZ] = {117, 234, 351, 468, 702, 936, 1053, 1170, 1404, 1560},
00188 [BW_160MHZ] = {234, 468, 702, 936, 1404, 1872, 2106, 2340, 2808, 3120},
00189 };
00190 #endif
00191
00193 #define TX_MIN_AMPDU_NB_PER_AC (3 * RW_USER_MAX)
00195 #define TX_AGG_DIVIDER (8 / RW_USER_MAX)
00197 #if (NX_TXDESC_CNT0 / TX_AGG_DIVIDER) >= TX_MIN_AMPDU_NB_PER_AC
00198 #define TX_MAX_AMPDU_NB_PER_AC0 (NX_TXDESC_CNT0 / TX_AGG_DIVIDER)
00199 #else
00200 #define TX_MAX_AMPDU_NB_PER_AC0 TX_MIN_AMPDU_NB_PER_AC
00201 #endif
00203 #if (NX_TXDESC_CNT1 / TX_AGG_DIVIDER) >= TX_MIN_AMPDU_NB_PER_AC
00204 #define TX_MAX_AMPDU_NB_PER_AC1 (NX_TXDESC_CNT1 / TX_AGG_DIVIDER)
00205 #else
00206 #define TX_MAX_AMPDU_NB_PER_AC1 TX_MIN_AMPDU_NB_PER_AC
00207 #endif
00209 #if (NX_TXDESC_CNT2 / TX_AGG_DIVIDER) >= TX_MIN_AMPDU_NB_PER_AC
00210 #define TX_MAX_AMPDU_NB_PER_AC2 (NX_TXDESC_CNT2 / TX_AGG_DIVIDER)
00211 #else
00212 #define TX_MAX_AMPDU_NB_PER_AC2 TX_MIN_AMPDU_NB_PER_AC
00213 #endif
00215 #if (NX_TXDESC_CNT3 / TX_AGG_DIVIDER) >= TX_MIN_AMPDU_NB_PER_AC
00216 #define TX_MAX_AMPDU_NB_PER_AC3 (NX_TXDESC_CNT3 / TX_AGG_DIVIDER)
00217 #else
00218 #define TX_MAX_AMPDU_NB_PER_AC3 TX_MIN_AMPDU_NB_PER_AC
00219 #endif
00220 #if NX_BEACONING
00222 #if (NX_TXDESC_CNT4 / TX_AGG_DIVIDER) > TX_MIN_AMPDU_NB_PER_AC
00223 #define TX_MAX_AMPDU_NB_PER_AC4 (NX_TXDESC_CNT4 / TX_AGG_DIVIDER)
00224 #else
00225 #define TX_MAX_AMPDU_NB_PER_AC4 TX_MIN_AMPDU_NB_PER_AC
00226 #endif
00227 #endif
00228
00230 #define TX_AMPDU_DESC_QUEUE_CNT (NX_TXQ_CNT + NX_MAC_HE)
00231
00232 #if NX_MAC_HE
00234 #define TX_MAX_AMPDU_NB_FOR_HE_TB 4
00236 #define TX_HE_TB_AMPDU_QUEUE_IDX (TX_AMPDU_DESC_QUEUE_CNT - 1)
00238 #define TX_AGG_FINISH_DUR 5
00239 #endif
00240
00241
00242
00243
00244
00246 static struct tx_agg_desc tx_agg_desc_array0[TX_MAX_AMPDU_NB_PER_AC0] __SHAREDRAM;
00248 static struct tx_agg_desc tx_agg_desc_array1[TX_MAX_AMPDU_NB_PER_AC1] __SHAREDRAM;
00250 static struct tx_agg_desc tx_agg_desc_array2[TX_MAX_AMPDU_NB_PER_AC2] __SHAREDRAM;
00252 static struct tx_agg_desc tx_agg_desc_array3[TX_MAX_AMPDU_NB_PER_AC3] __SHAREDRAM;
00253 #if NX_BEACONING
00255 static struct tx_agg_desc tx_agg_desc_array4[TX_MAX_AMPDU_NB_PER_AC4] __SHAREDRAM;
00256 #endif
00257 #if NX_MAC_HE
00259 static struct tx_agg_desc tx_agg_desc_array5[TX_MAX_AMPDU_NB_FOR_HE_TB] __SHAREDRAM;
00260 #endif
00261
00263 static const struct tx_agg_desc * const tx_agg_desc_array[TX_AMPDU_DESC_QUEUE_CNT] =
00264 {
00265 tx_agg_desc_array0,
00266 tx_agg_desc_array1,
00267 tx_agg_desc_array2,
00268 tx_agg_desc_array3,
00269 #if NX_BEACONING
00270 tx_agg_desc_array4,
00271 #endif
00272 #if NX_MAC_HE
00273 tx_agg_desc_array5,
00274 #endif
00275 };
00276
00278 static const int tx_agg_desc_cnt[TX_AMPDU_DESC_QUEUE_CNT] =
00279 {
00280 TX_MAX_AMPDU_NB_PER_AC0,
00281 TX_MAX_AMPDU_NB_PER_AC1,
00282 TX_MAX_AMPDU_NB_PER_AC2,
00283 TX_MAX_AMPDU_NB_PER_AC3,
00284 #if NX_BEACONING
00285 TX_MAX_AMPDU_NB_PER_AC4,
00286 #endif
00287 #if NX_MAC_HE
00288 TX_MAX_AMPDU_NB_FOR_HE_TB,
00289 #endif
00290 };
00291
00293 struct co_list tx_agg_desc_pool[TX_AMPDU_DESC_QUEUE_CNT];
00294
00295
00296
00297
00298
00299
00309 static bool txl_desc_is_agg(struct txdesc *txdesc, struct tx_agg_desc * agg_desc)
00310 {
00311 if (is_mpdu_agg(txdesc) && !is_mpdu_first(txdesc))
00312 {
00313
00314 if ( (agg_desc->sta_idx == txdesc->host.staid) &&
00315 (agg_desc->tid == txdesc->host.tid) )
00316 {
00317 return true;
00318 }
00319 }
00320 return false;
00321 }
00322
00323 #if NX_UMAC_PRESENT
00324
00334 static bool txl_ampdu_has_ht_vht_rate(struct txdesc *txdesc)
00335 {
00336 return (((txdesc->umac.phy_flags & FORMAT_MOD_TX_RCX_MASK)
00337 >> FORMAT_MOD_TX_RCX_OFT) > FORMATMOD_NON_HT_DUP_OFDM);
00338 }
00339 #endif
00340
00351 static uint32_t txl_vht_idx_to_32us_len_get(int base_idx, uint8_t bw)
00352 {
00353 int idx = base_idx | (bw << 1);
00354 return ((uint32_t)TX_VHT_RATE_TO_32US_LEN[idx]);
00355 }
00356
00367 static uint16_t txl_vht_idx_to_1us_len_get(int base_idx, uint8_t bw)
00368 {
00369 int idx = base_idx | (bw << 1);
00370 return ((uint32_t)TX_VHT_RATE_TO_MIN_SEP[idx]);
00371 }
00372
00387 static int txl_ht_vht_ampdu_param_get(struct txdesc *txdesc,
00388 uint8_t format_mod,
00389 uint32_t *max_len_sta,
00390 uint32_t *nss)
00391 {
00392 uint32_t phy_flags = txdesc->umac.phy_flags;
00393 uint32_t mcs_idx = (phy_flags & MCS_INDEX_TX_RCX_MASK) >> MCS_INDEX_TX_RCX_OFT;
00394 uint32_t sgi = (phy_flags & SHORT_GI_TX_RCX_MASK) >> SHORT_GI_TX_RCX_OFT;
00395 struct sta_info_tag *sta = &sta_info_tab[txdesc->host.staid];
00396
00397
00398 if (format_mod == FORMATMOD_VHT)
00399 {
00400
00401 *nss = ((mcs_idx & VHT_NSS_MASK) >> VHT_NSS_OFT) + 1;
00402
00403
00404 mcs_idx = (mcs_idx & VHT_MCS_MASK) >> VHT_MCS_OFT;
00405
00406
00407 ASSERT_ERR((*nss > 0) && (*nss <= 4));
00408 ASSERT_ERR(mcs_idx <= 9);
00409
00410
00411 *max_len_sta = sta->ampdu_size_max_vht;
00412 }
00413 else
00414 {
00415
00416 ASSERT_ERR(mcs_idx <= 31);
00417
00418
00419 *nss = ((mcs_idx & HT_NSS_MASK) >> HT_NSS_OFT) + 1;
00420
00421
00422 mcs_idx = (mcs_idx & HT_MCS_MASK) >> HT_MCS_OFT;
00423
00424
00425 *max_len_sta = sta->ampdu_size_max_ht;
00426 }
00427
00428
00429
00430
00431 return ((mcs_idx << 3) | sgi);
00432 }
00433
00443 static void txl_ampdu_constraints_get(struct txdesc *txdesc,
00444 uint8_t ac,
00445 struct txl_agg_build_tag *agg)
00446 {
00447 int rate_idx;
00448 uint32_t max_len_sta;
00449 uint32_t max_len_phy;
00450 uint32_t nss;
00451 uint32_t bw = (txdesc->umac.phy_flags & BW_TX_RCX_MASK) >> BW_TX_RCX_OFT;
00452 struct sta_info_tag *sta = &sta_info_tab[txdesc->host.staid];
00453 #if NX_BW_LEN_ADAPT
00454 int i;
00455 #endif
00456 uint8_t format_mod;
00457 uint32_t (*idx_to_32us_len)(int, uint8_t);
00458 uint16_t (*idx_to_1us_len)(int, uint8_t);
00459
00460
00461 format_mod = (txdesc->umac.phy_flags & FORMAT_MOD_TX_RCX_MASK) >> FORMAT_MOD_TX_RCX_OFT;
00462
00463
00464 ASSERT_ERR(format_mod > FORMATMOD_NON_HT_DUP_OFDM);
00465
00466 #if NX_MAC_HE
00467 if (format_mod == FORMATMOD_HE_SU)
00468 {
00469
00470 rate_idx = txl_he_ampdu_param_get(txdesc, format_mod, &max_len_sta, &nss);
00471 idx_to_32us_len = txl_he_idx_to_32us_len_get;
00472 idx_to_1us_len = txl_he_idx_to_1us_len_get;
00473 }
00474 else
00475 #endif
00476 {
00477
00478 rate_idx = txl_ht_vht_ampdu_param_get(txdesc, format_mod, &max_len_sta, &nss);
00479 idx_to_32us_len = txl_vht_idx_to_32us_len_get;
00480 idx_to_1us_len = txl_vht_idx_to_1us_len_get;
00481 }
00482
00483
00484 agg->bw = bw;
00485
00486 #if NX_BW_LEN_ADAPT
00487 agg->bw_idx = 0;
00488
00489
00490 for (i = 0; i <= agg->bw; i++)
00491 {
00492
00493 max_len_phy = idx_to_32us_len(rate_idx, i) * nss * mm_env.ampdu_max_dur[ac];
00494
00495
00496 agg->max_len[i] = co_min(max_len_phy, max_len_sta);
00497 }
00498
00499 #else
00500
00501 max_len_phy = idx_to_32us_len(rate_idx, 0) * nss * mm_env.ampdu_max_dur[ac];
00502
00503
00504 agg->max_len[0] = co_min(max_len_phy, max_len_sta);
00505 #endif
00506
00507
00508 agg->mmss_bytes = idx_to_1us_len(rate_idx, bw) * nss *
00509 (uint16_t)sta->ampdu_spacing_min;
00510
00511
00512 agg->max_cnt = sta_mgmt_get_tx_buff_size(txdesc->host.staid, txdesc->host.tid);
00513 }
00514
00525 static void txl_fill_bar(struct tx_agg_desc *agg_desc, uint16_t sn,
00526 uint8_t staid, uint8_t tid, uint8_t bw)
00527 {
00528 struct tx_hd *bar_thd = &agg_desc->bar_thd;
00529 struct tx_policy_tbl *bar_pol = &agg_desc->bar_pol_tbl;
00530 struct bar_frame *bar_payl = &agg_desc->bar_payl;
00531 struct sta_info_tag *sta = &sta_info_tab[staid];
00532 struct vif_info_tag *vif = &vif_info_tab[sta->inst_nbr];
00533
00534
00535
00536
00537
00538 bar_payl->h.addr1 = sta->mac_addr;
00539
00540 bar_payl->h.addr2 = vif->mac_addr;
00541
00542
00543 bar_payl->bar_cntrl = BAR_CNTL_COMPRESSED_BIT|(tid << BAR_CNTL_TID_OFT);
00544
00545
00546 bar_payl->bar_information = sn << 4;
00547
00548
00549
00550
00551
00552 bar_thd->nextfrmexseq_ptr = 0;
00553
00554
00555 bar_thd->statinfo = 0;
00556
00557
00558
00559
00560
00561 bar_pol->powercntrlinfo[0] = TX_PWR_LEVEL_SET(nxmac_ofdm_max_pwr_level_getf());
00562
00563 bar_pol->ratecntrlinfo[0] = (bw << BW_TX_RCX_OFT) |
00564 (FORMATMOD_NON_HT_DUP_OFDM << FORMAT_MOD_TX_RCX_OFT) |
00565 (HW_RATE_24MBPS << MCS_INDEX_TX_RCX_OFT);
00566 }
00567
00573 static void txl_agg_hwdesc_init(void)
00574 {
00575
00576 memset(tx_agg_desc_pool, 0, sizeof(tx_agg_desc_pool));
00577
00578
00579 for (int i = 0; i < TX_AMPDU_DESC_QUEUE_CNT; i++)
00580 {
00581 struct co_list *list = &tx_agg_desc_pool[i];
00582
00583 memset((void *)tx_agg_desc_array[i], 0, tx_agg_desc_cnt[i] * sizeof(struct tx_agg_desc));
00584 for (int j = 0; j < tx_agg_desc_cnt[i]; j++)
00585 {
00586 struct tx_agg_desc *agg_desc = (struct tx_agg_desc *)&tx_agg_desc_array[i][j];
00587 struct tx_hd *a_thd = &agg_desc->a_thd;
00588 struct tx_hd *bar_thd = &agg_desc->bar_thd;
00589 struct bar_frame *bar_payl = &agg_desc->bar_payl;
00590 struct tx_policy_tbl *bar_pol = &agg_desc->bar_pol_tbl;
00591
00592
00593 agg_desc->free_list = list;
00594
00595
00596 bar_payl->h.fctl = (MAC_FCTRL_CTRL_T | MAC_FCTRL_BAR_ST);
00597 bar_payl->h.durid = 0x0500;
00598
00599
00600 a_thd->upatterntx = TX_HEADER_DESC_PATTERN;
00601 a_thd->frmlifetime = 0;
00602 a_thd->macctrlinfo2 = WHICHDESC_AMPDU_EXTRA | INTERRUPT_EN_TX;
00603 a_thd->optlen[0] = 0;
00604 a_thd->optlen[1] = 0;
00605 a_thd->optlen[2] = 0;
00606
00607
00608 bar_thd->upatterntx = TX_HEADER_DESC_PATTERN;
00609 bar_thd->frmlifetime = 0;
00610 bar_thd->nextmpdudesc_ptr = 0;
00611 bar_thd->policyentryaddr = CPU2HW(&agg_desc->bar_pol_tbl);
00612 bar_thd->datastartptr = CPU2HW(bar_payl);
00613 bar_thd->dataendptr = (uint32_t)bar_thd->datastartptr + BAR_FRM_LEN_WITH_FCS - 1;
00614 bar_thd->first_pbd_ptr = 0;
00615 bar_thd->optlen[0] = 0;
00616 bar_thd->optlen[1] = 0;
00617 bar_thd->optlen[2] = 0;
00618
00619
00620 bar_thd->frmlen = BAR_FRM_LEN_WITH_FCS;
00621
00622 bar_thd->phyctrlinfo = 0;
00623
00624 bar_thd->macctrlinfo1 = EXPECTED_ACK_COMPRESSED_BLOCK_ACK;
00625
00626 bar_thd->macctrlinfo2 = INTERRUPT_EN_TX | WHICHDESC_UNFRAGMENTED_MSDU |
00627 FRM_TYPE_CNTL | FRM_CNTL_SUBTYPE_BAR| TS_VALID_BIT;
00628
00629
00630 bar_pol->upatterntx = POLICY_TABLE_PATTERN;
00631 bar_pol->phycntrlinfo1 = phy_get_ntx() << NX_TX_PT_OFT;
00632 bar_pol->phycntrlinfo2 = TX_NTX_2_ANTENNA_SET(phy_get_ntx());
00633 bar_pol->maccntrlinfo1 = 0;
00634 bar_pol->maccntrlinfo2 = 0xFFFF0704;
00635
00636
00637 co_list_push_back(list, (struct co_list_hdr *) agg_desc);
00638 }
00639 }
00640 }
00641
00647 static void txl_agg_hwdesc_reset(void)
00648 {
00649
00650 for (int i = 0; i < TX_AMPDU_DESC_QUEUE_CNT; i++)
00651 {
00652 struct co_list *list = &tx_agg_desc_pool[i];
00653
00654
00655 co_list_init(list);
00656
00657 for (int j = 0; j < tx_agg_desc_cnt[i]; j++)
00658 {
00659 struct tx_agg_desc *agg_desc = (struct tx_agg_desc *)&tx_agg_desc_array[i][j];
00660
00661
00662 co_list_push_back(list, (struct co_list_hdr *) agg_desc);
00663 }
00664 }
00665 }
00666
00667 #if NX_MAC_HE
00668
00679 static bool txl_agg_is_int_or_mgt(struct txdesc *txdesc)
00680 {
00681 if (is_int_frame(txdesc))
00682 return true;
00683
00684 #if NX_UMAC_PRESENT
00685 if (txdesc->host.flags & TXU_CNTRL_MGMT)
00686 return true;
00687 #endif
00688
00689 return false;
00690 }
00691
00703 static void txl_agg_set_uph(struct txdesc *txdesc)
00704 {
00705
00706
00707
00708 while(1)
00709 {
00710
00711
00712 if (!txl_buffer_update_htc(&txdesc->lmac.hw_desc->thd, txl_he_tb_uph_get()))
00713 break;
00714
00715
00716 if (is_mpdu_last(txdesc))
00717 break;
00718
00719
00720 txdesc = tx_desc_next(txdesc);
00721
00722
00723
00724 ASSERT_ERR(txdesc != NULL);
00725 }
00726 }
00727
00750 static struct tx_hd *txl_agg_split(struct txdesc *txdesc, struct txdesc **txdesc_next,
00751 uint32_t max_len, uint16_t min_mpdu_len, uint8_t ac)
00752 {
00753 struct txl_list *txlist = &txl_cntrl_env.txlist[ac];
00754 struct tx_agg_desc *agg_desc_old = txdesc->lmac.agg_desc;
00755 struct tx_agg_desc *agg_desc_new;
00756 struct tx_hd *thd_tb;
00757 struct tx_hd *a_thd_new, *a_thd_old;
00758 struct txdesc *txdesc_prev = NULL;
00759 #if NX_UMAC_PRESENT
00760 uint8_t current_cnt;
00761 #endif
00762 bool split = true;
00763 bool timeout = false;
00764
00765 agg_desc_new = txl_agg_desc_alloc(TX_HE_TB_AMPDU_QUEUE_IDX);
00766 ASSERT_ERR(agg_desc_new != NULL);
00767
00768
00769 agg_desc_new->status = agg_desc_old->status;
00770 agg_desc_new->sta_idx = agg_desc_old->sta_idx;
00771 agg_desc_new->tid = agg_desc_old->tid;
00772 agg_desc_new->user_cnt = 1;
00773
00774
00775 a_thd_old = &agg_desc_old->a_thd;
00776 a_thd_new = &agg_desc_new->a_thd;
00777 a_thd_new->phyctrlinfo = a_thd_old->phyctrlinfo;
00778 a_thd_new->macctrlinfo1 = a_thd_old->macctrlinfo1;
00779 a_thd_new->macctrlinfo2 = a_thd_old->macctrlinfo2;
00780 a_thd_new->nextmpdudesc_ptr = a_thd_old->nextmpdudesc_ptr;
00781 a_thd_new->policyentryaddr = a_thd_old->policyentryaddr;
00782 a_thd_new->frmlen = 0;
00783 thd_tb = a_thd_new;
00784
00785
00786 #if NX_UMAC_PRESENT
00787 current_cnt = 0;
00788 #endif
00789
00790
00791
00792
00793 while(1)
00794 {
00795 struct tx_hd *thd = &txdesc->lmac.hw_desc->thd;
00796 uint16_t nb_delims_new, nb_delims_old;
00797 uint16_t subfrm_len_new, subfrm_len_old;
00798
00799
00800 nb_delims_old = (txdesc->umac.flags & NB_BLANK_DELIM_MSK) >> NB_BLANK_DELIM_OFT;
00801 subfrm_len_old = txl_mpdu_subframe_len(thd) + nb_delims_old * DELIMITER_LEN;
00802 if (subfrm_len_old < min_mpdu_len)
00803 {
00804
00805 nb_delims_new = txl_agg_mpdu_nb_delims(thd, min_mpdu_len);
00806 subfrm_len_new = txl_mpdu_subframe_len(thd) + nb_delims_new * DELIMITER_LEN;
00807 }
00808 else
00809 {
00810
00811 subfrm_len_new = subfrm_len_old;
00812 }
00813
00814
00815
00816 if (((a_thd_new->frmlen + subfrm_len_new) > max_len) || timeout)
00817 {
00818
00819 if (txdesc_prev == NULL)
00820 {
00821
00822 txl_he_mu_edca_blocked(a_thd_old, ac);
00823
00824
00825 txl_agg_desc_free(agg_desc_new);
00826
00827 return NULL;
00828 }
00829
00830 else if (is_mpdu_first(txdesc_prev))
00831 {
00832
00833 txl_agg_change_to_singleton(txdesc_prev, true);
00834
00835
00836
00837 txdesc_prev->lmac.agg_desc = agg_desc_new;
00838
00839
00840
00841 thd_tb = &txdesc_prev->lmac.hw_desc->thd;
00842 break;
00843 }
00844 else
00845 {
00846 struct tx_hd *thd_last = &txdesc_prev->lmac.hw_desc->thd;
00847 #if NX_UMAC_PRESENT
00848 struct tx_cfm_tag *cfm = txl_cfm_tag_get(txdesc_prev);
00849 cfm->ampdu_size = current_cnt;
00850 #endif
00851
00852
00853 agg_desc_new->txdesc_last = txdesc_prev;
00854
00855
00856 set_mpdu_pos(txdesc_prev, WHICHDESC_AMPDU_LAST);
00857
00858
00859 thd_last->macctrlinfo2 = txdesc_prev->umac.flags | INTERRUPT_EN_TX;
00860 thd_last->nextmpdudesc_ptr = 0;
00861 break;
00862 }
00863 }
00864
00865 PROF_AGG_ADD_MPDU_SET();
00866
00867
00868 txl_buffer_update_htc(thd, txl_he_tb_uph_get());
00869
00870
00871 txdesc->lmac.agg_desc = agg_desc_new;
00872
00873 if (subfrm_len_old < min_mpdu_len)
00874 {
00875
00876 txdesc->umac.flags = thd->macctrlinfo2;
00877 txdesc->umac.flags &= ~NB_BLANK_DELIM_MSK;
00878 txdesc->umac.flags |= (nb_delims_new << NB_BLANK_DELIM_OFT);
00879 thd->macctrlinfo2 = txdesc->umac.flags | INTERRUPT_EN_TX;
00880 }
00881 else
00882 {
00883 subfrm_len_old = subfrm_len_new;
00884 }
00885
00886
00887 a_thd_new->frmlen += subfrm_len_new;
00888
00889
00890 a_thd_old->frmlen -= subfrm_len_old;
00891
00892 PROF_AGG_ADD_MPDU_CLR();
00893
00894
00895 if (is_mpdu_last(txdesc))
00896 {
00897 agg_desc_new->txdesc_last = txdesc;
00898 split = false;
00899 break;
00900 }
00901
00902 txdesc_prev = txdesc;
00903 #if NX_UMAC_PRESENT
00904 current_cnt++;
00905 #endif
00906
00907
00908 if (nxmac_tx_hetb_rem_dur_getf() < TX_HE_TB_PROG_TIME)
00909 timeout = true;
00910
00911 txdesc = tx_desc_next(txdesc);
00912
00913
00914
00915
00916 ASSERT_ERR(txdesc != NULL);
00917 }
00918
00919
00920
00921
00922 ASSERT_ERR(co_list_pick(&txlist->aggregates) == &agg_desc_old->list_hdr);
00923
00924
00925
00926
00927 if (split)
00928 {
00929
00930 txlist->ppdu_cnt++;
00931
00932
00933
00934
00935
00936 if (is_mpdu_last(txdesc))
00937 {
00938 co_list_pop_front(&txlist->aggregates);
00939 }
00940 *txdesc_next = txdesc;
00941 }
00942 else
00943 {
00944
00945 co_list_pop_front(&txlist->aggregates);
00946 txl_agg_desc_free(agg_desc_old);
00947 *txdesc_next = tx_desc_next(txdesc);
00948
00949
00950 txdesc->lmac.hw_desc->thd.nextmpdudesc_ptr = 0;
00951 }
00952
00953
00954 co_list_push_front(&txlist->aggregates, &agg_desc_new->list_hdr);
00955
00956 return (thd_tb);
00957 }
00958
00983 static bool txl_agg_he_tb_prep_for_cat(struct txdesc *txdesc1, struct txdesc *txdesc2,
00984 uint8_t ac)
00985 {
00986 struct txl_list *txlist = &txl_cntrl_env.txlist[ac];
00987 struct txl_agg_build_tag *agg;
00988 struct txdesc *txdesc_first, *txdesc_last;
00989 struct tx_hd *thd;
00990 struct tx_pbd *tbd;
00991 struct txl_buffer_tag *buffer;
00992 #if NX_UMAC_PRESENT
00993 struct tx_cfm_tag *cfm;
00994 #endif
00995 struct tx_agg_desc *agg_desc = txdesc2->lmac.agg_desc;
00996
00997
00998 if ((txdesc1->host.staid != txdesc2->host.staid) ||
00999 (txdesc1->host.tid != txdesc2->host.tid))
01000 return false;
01001
01002
01003
01004
01005
01006
01007 if ((txl_buffer_get(txdesc2) && !(agg_desc->status & AGG_FIRST_DOWNLOADED)) ||
01008 ((agg_desc->status & (AGG_ALLOC | AGG_DOWNLOADED)) == AGG_ALLOC))
01009 return false;
01010
01011 if (agg_desc->status & AGG_FORMATTED)
01012 return true;
01013
01014 agg = &txlist->agg[0];
01015
01016
01017 if (agg->curr_cnt == 1)
01018 return false;
01019
01020 txdesc_last = agg->txdesc_last;
01021 thd = &txdesc_last->lmac.hw_desc->thd;
01022 buffer = txl_buffer_get(txdesc_last);
01023 tbd = HW2CPU(thd->first_pbd_ptr);
01024
01025
01026
01027 if ((buffer != NULL) && (tbd->upatterntx != TX_PAYLOAD_DESC_PATTERN))
01028 return false;
01029
01030
01031 if (nxmac_tx_hetb_rem_dur_getf() <= (TX_HE_TB_PROG_TIME + TX_AGG_FINISH_DUR))
01032 return false;
01033
01034
01035 PROF_AGG_FINISH_AMPDU_SET();
01036
01037 txdesc_first = txdesc2;
01038 #if NX_UMAC_PRESENT
01039 cfm = txl_cfm_tag_get(txdesc_last);
01040 #endif
01041
01042
01043 set_mpdu_pos(txdesc_last, WHICHDESC_AMPDU_LAST);
01044
01045 agg_desc->txdesc_last = txdesc_last;
01046 txl_he_txop_dur_rtscts_thres_ampdu_check(agg->txdesc_first);
01047
01048 #if NX_UMAC_PRESENT
01049 cfm->ampdu_size = agg->curr_cnt;
01050 #endif
01051
01052
01053 txl_fill_bar(agg_desc, txdesc_last->umac.sn_win, agg_desc->sta_idx, agg_desc->tid, agg->bw);
01054
01055
01056 thd->nextmpdudesc_ptr = CPU2HW(&agg_desc->bar_thd);
01057
01058
01059 thd->macctrlinfo2 = txdesc_last->umac.flags | INTERRUPT_EN_TX;
01060
01061
01062 agg_desc->status |= AGG_FORMATTED;
01063
01064
01065
01066 if (buffer != NULL)
01067 {
01068
01069 if (!(agg_desc->status & AGG_ALLOC))
01070 {
01071
01072 if (!(agg_desc->status & AGG_FIRST_DOWNLOADED))
01073 {
01074
01075
01076 struct txl_buffer_tag *buffer_first = txl_buffer_get(txdesc_first);
01077 buffer_first->flags |= BUF_ALLOC_OK;
01078 }
01079 else
01080
01081
01082 agg_desc->status |= AGG_DOWNLOADED;
01083 }
01084 }
01085
01086
01087 if (agg_desc->status & AGG_DOWNLOADED)
01088 {
01089
01090
01091 struct tx_policy_tbl *pt = HW2CPU(agg_desc->a_thd.policyentryaddr);
01092 pt->ratecntrlinfo[0] = agg->txdesc_first->umac.phy_flags;
01093 }
01094
01095
01096 co_list_push_back(&txl_cntrl_env.txlist[ac].aggregates, &agg_desc->list_hdr);
01097
01098
01099
01100 txl_cntrl_env.txlist[ac].ppdu_cnt++;
01101
01102
01103 agg->desc = NULL;
01104
01105
01106 PROF_AGG_FINISH_AMPDU_CLR();
01107
01108 return true;
01109 }
01110
01132 static bool txl_agg_he_tb_cat_ampdu_mpdu(struct txdesc *txdesc_ampdu, struct txdesc **txdesc_next,
01133 uint32_t max_len, uint16_t min_mpdu_len, uint8_t ac)
01134 {
01135 struct tx_agg_desc *agg_desc = txdesc_ampdu->lmac.agg_desc;
01136 struct txdesc *txdesc_mpdu = *txdesc_next;
01137 struct txdesc *txdesc_last = agg_desc->txdesc_last;
01138 struct txl_list *txlist = &txl_cntrl_env.txlist[ac];
01139 struct tx_hd *thd = &txdesc_mpdu->lmac.hw_desc->thd;
01140 struct tx_hd *thd_last = &txdesc_last->lmac.hw_desc->thd;
01141 uint16_t nb_delims_new, subfrm_len_new;
01142 struct tx_hd *a_thd;
01143
01144
01145 if ((agg_desc->sta_idx != txdesc_mpdu->host.staid) ||
01146 (agg_desc->tid != txdesc_mpdu->host.tid))
01147 return false;
01148
01149 a_thd = &agg_desc->a_thd;
01150 thd = &txdesc_mpdu->lmac.hw_desc->thd;
01151
01152
01153 txl_buffer_add_htc(thd);
01154
01155
01156 nb_delims_new = txl_agg_mpdu_nb_delims(thd, min_mpdu_len);
01157 subfrm_len_new = txl_mpdu_subframe_len(thd) + nb_delims_new * DELIMITER_LEN;
01158
01159 if ((a_thd->frmlen + subfrm_len_new) > max_len)
01160 return false;
01161
01162
01163 txlist->ppdu_cnt--;
01164
01165 set_mpdu_pos(txdesc_last, WHICHDESC_AMPDU_INT);
01166 thd_last->macctrlinfo2 = txdesc_last->umac.flags | INTERRUPT_EN_TX;
01167 thd_last->nextmpdudesc_ptr = CPU2HW(thd);
01168
01169 set_mpdu_pos(txdesc_mpdu, WHICHDESC_AMPDU_LAST);
01170 txdesc_mpdu->umac.flags |= (nb_delims_new << NB_BLANK_DELIM_OFT) | UNDER_BA_SETUP_BIT;
01171 thd->macctrlinfo2 = txdesc_mpdu->umac.flags | INTERRUPT_EN_TX;
01172 thd->nextfrmexseq_ptr = 0;
01173 thd->policyentryaddr = 0;
01174
01175 a_thd->frmlen += subfrm_len_new;
01176
01177 txdesc_mpdu->lmac.agg_desc = agg_desc;
01178 agg_desc->txdesc_last = txdesc_mpdu;
01179
01180 *txdesc_next = tx_desc_next(agg_desc->txdesc_last);
01181
01182
01183 txl_buffer_update_htc(thd, txl_he_tb_uph_get());
01184
01185 #if NX_UMAC_PRESENT
01186 txl_cfm_tag_get(txdesc_mpdu)->ampdu_size = txl_cfm_tag_get(txdesc_last)->ampdu_size + 1;
01187 #endif
01188
01189 return true;
01190 }
01191
01213 static bool txl_agg_he_tb_cat_mpdu_ampdu(struct txdesc *txdesc_mpdu, struct txdesc **txdesc_next,
01214 uint32_t max_len, uint16_t min_mpdu_len, uint8_t ac)
01215 {
01216 struct txdesc *txdesc_ampdu = *txdesc_next;
01217 struct tx_agg_desc *agg_desc = txdesc_ampdu->lmac.agg_desc;
01218 struct txl_list *txlist = &txl_cntrl_env.txlist[ac];
01219 struct tx_hd *thd = &txdesc_mpdu->lmac.hw_desc->thd;
01220 uint16_t nb_delims_new, subfrm_len_new;
01221 struct tx_hd *a_thd;
01222
01223
01224 if (!txl_agg_he_tb_prep_for_cat(txdesc_mpdu, txdesc_ampdu, ac))
01225 return false;
01226
01227 a_thd = &agg_desc->a_thd;
01228 thd = &txdesc_mpdu->lmac.hw_desc->thd;
01229
01230
01231 nb_delims_new = txl_agg_mpdu_nb_delims(thd, min_mpdu_len);
01232 subfrm_len_new = txl_mpdu_subframe_len(thd) + nb_delims_new * DELIMITER_LEN;
01233
01234
01235 txlist->ppdu_cnt--;
01236
01237 thd->nextmpdudesc_ptr = a_thd->nextmpdudesc_ptr;
01238 a_thd->frmlen += subfrm_len_new;
01239 a_thd->nextmpdudesc_ptr = CPU2HW(thd);
01240
01241 txdesc_mpdu->lmac.agg_desc = agg_desc;
01242 set_mpdu_pos(txdesc_mpdu, WHICHDESC_AMPDU_FIRST);
01243 txdesc_mpdu->umac.flags |= (nb_delims_new << NB_BLANK_DELIM_OFT) | UNDER_BA_SETUP_BIT;
01244 thd->macctrlinfo2 = txdesc_mpdu->umac.flags | INTERRUPT_EN_TX;
01245 thd->policyentryaddr = 0;
01246
01247 set_mpdu_pos(txdesc_ampdu, WHICHDESC_AMPDU_INT);
01248 txdesc_ampdu->lmac.hw_desc->thd.macctrlinfo2 = txdesc_ampdu->umac.flags | INTERRUPT_EN_TX;
01249
01250 #if NX_UMAC_PRESENT
01251 txl_cfm_tag_get(agg_desc->txdesc_last)->ampdu_size++;
01252 #endif
01253
01254 if (a_thd->frmlen > max_len)
01255 {
01256 txl_agg_split(txdesc_mpdu, txdesc_next, max_len, min_mpdu_len, ac);
01257 return false;
01258 }
01259
01260
01261 txl_agg_set_uph(txdesc_ampdu);
01262
01263 *txdesc_next = tx_desc_next(agg_desc->txdesc_last);
01264
01265 return true;
01266 }
01267
01291 static bool txl_agg_he_tb_cat_ampdu(struct txdesc *txdesc, struct txdesc **txdesc_next,
01292 uint32_t max_len, uint16_t min_mpdu_len, uint8_t ac)
01293 {
01294 struct txl_list *txlist = &txl_cntrl_env.txlist[ac];
01295 struct txdesc *txdesc_n = *txdesc_next;
01296 struct tx_agg_desc *agg_desc_n = txdesc_n->lmac.agg_desc;
01297 struct tx_agg_desc *agg_desc = txdesc->lmac.agg_desc;
01298 struct tx_hd *a_thd, *a_thd_n;
01299 struct txdesc *txdesc_last = agg_desc->txdesc_last;
01300 struct tx_hd *thd_n = &txdesc_n->lmac.hw_desc->thd;
01301 bool split = true;
01302 struct txdesc *txdesc_prev = NULL;
01303 #if NX_UMAC_PRESENT
01304 uint8_t current_cnt;
01305 #endif
01306
01307
01308 co_list_pop_front(&txlist->aggregates);
01309
01310
01311 if (!txl_agg_he_tb_prep_for_cat(txdesc, txdesc_n, ac))
01312 {
01313 co_list_push_front(&txlist->aggregates, &agg_desc->list_hdr);
01314 return false;
01315 }
01316
01317 a_thd_n = &agg_desc_n->a_thd;
01318 a_thd = &agg_desc->a_thd;
01319
01320 #if NX_UMAC_PRESENT
01321 current_cnt = txl_cfm_tag_get(txdesc_last)->ampdu_size;
01322 #endif
01323
01324
01325 txdesc_last->lmac.hw_desc->thd.nextmpdudesc_ptr = CPU2HW(thd_n);
01326 set_mpdu_pos(txdesc_last, WHICHDESC_AMPDU_INT);
01327 txdesc_last->lmac.hw_desc->thd.macctrlinfo2 = txdesc_last->umac.flags | INTERRUPT_EN_TX;
01328 set_mpdu_pos(txdesc_n, WHICHDESC_AMPDU_INT);
01329 thd_n->macctrlinfo2 = (*txdesc_next)->umac.flags | INTERRUPT_EN_TX;
01330
01331
01332
01333
01334 while(1)
01335 {
01336 struct tx_hd *thd = &txdesc_n->lmac.hw_desc->thd;
01337 uint16_t nb_delims_new, nb_delims_old;
01338 uint16_t subfrm_len_new, subfrm_len_old;
01339
01340
01341 nb_delims_old = (txdesc_n->umac.flags & NB_BLANK_DELIM_MSK) >> NB_BLANK_DELIM_OFT;
01342 subfrm_len_old = txl_mpdu_subframe_len(thd) + nb_delims_old * DELIMITER_LEN;
01343 if (subfrm_len_old < min_mpdu_len)
01344 {
01345
01346 nb_delims_new = txl_agg_mpdu_nb_delims(thd, min_mpdu_len);
01347 subfrm_len_new = txl_mpdu_subframe_len(thd) + nb_delims_new * DELIMITER_LEN;
01348 }
01349 else
01350 {
01351
01352 subfrm_len_new = subfrm_len_old;
01353 }
01354
01355
01356
01357 if (((a_thd->frmlen + subfrm_len_new) > max_len) ||
01358 (nxmac_tx_hetb_rem_dur_getf() < TX_HE_TB_PROG_TIME))
01359 {
01360
01361 if (txdesc_prev == NULL)
01362 {
01363
01364
01365 txdesc_last->lmac.hw_desc->thd.nextmpdudesc_ptr = 0;
01366 set_mpdu_pos(txdesc_last, WHICHDESC_AMPDU_LAST);
01367 txdesc_last->lmac.hw_desc->thd.macctrlinfo2 = txdesc_last->umac.flags | INTERRUPT_EN_TX;
01368 set_mpdu_pos(txdesc_n, WHICHDESC_AMPDU_FIRST);
01369 thd->macctrlinfo2 = txdesc_n->umac.flags | INTERRUPT_EN_TX;
01370
01371 co_list_push_front(&txlist->aggregates, &agg_desc->list_hdr);
01372 *txdesc_next = txdesc_n;
01373 return false;
01374 }
01375 else
01376 {
01377 struct tx_hd *thd_last = &txdesc_prev->lmac.hw_desc->thd;
01378 #if NX_UMAC_PRESENT
01379 struct tx_cfm_tag *cfm = txl_cfm_tag_get(txdesc_prev);
01380 cfm->ampdu_size = current_cnt;
01381 #endif
01382
01383
01384 agg_desc->txdesc_last = txdesc_prev;
01385
01386
01387 set_mpdu_pos(txdesc_prev, WHICHDESC_AMPDU_LAST);
01388
01389
01390 thd_last->macctrlinfo2 = txdesc_prev->umac.flags | INTERRUPT_EN_TX;
01391 thd_last->nextmpdudesc_ptr = 0;
01392 break;
01393 }
01394 }
01395
01396 PROF_AGG_ADD_MPDU_SET();
01397
01398
01399 txl_buffer_update_htc(thd, txl_he_tb_uph_get());
01400
01401
01402 txdesc_n->lmac.agg_desc = agg_desc;
01403
01404 if (subfrm_len_old < min_mpdu_len)
01405 {
01406
01407 txdesc_n->umac.flags = thd->macctrlinfo2;
01408 txdesc_n->umac.flags &= ~NB_BLANK_DELIM_MSK;
01409 txdesc_n->umac.flags |= (nb_delims_new << NB_BLANK_DELIM_OFT);
01410 thd->macctrlinfo2 = txdesc_n->umac.flags | INTERRUPT_EN_TX;
01411 }
01412 else
01413 {
01414 subfrm_len_old = subfrm_len_new;
01415 }
01416
01417
01418 a_thd->frmlen += subfrm_len_new;
01419
01420
01421 a_thd_n->frmlen -= subfrm_len_old;
01422
01423 PROF_AGG_ADD_MPDU_CLR();
01424
01425
01426 if (is_mpdu_last(txdesc_n))
01427 {
01428 agg_desc->txdesc_last = txdesc_n;
01429 split = false;
01430 break;
01431 }
01432
01433 txdesc_prev = txdesc_n;
01434
01435 #if NX_UMAC_PRESENT
01436 current_cnt++;
01437 #endif
01438
01439 txdesc_n = tx_desc_next(txdesc_n);
01440
01441
01442
01443
01444 ASSERT_ERR(txdesc_n != NULL);
01445 }
01446
01447
01448
01449
01450 if (split)
01451 {
01452
01453
01454
01455
01456 if (is_mpdu_last(txdesc_n))
01457 {
01458 co_list_pop_front(&txlist->aggregates);
01459 }
01460 *txdesc_next = txdesc_n;
01461 }
01462 else
01463 {
01464
01465 txlist->ppdu_cnt--;
01466
01467
01468 co_list_pop_front(&txlist->aggregates);
01469 txl_agg_desc_free(agg_desc_n);
01470 *txdesc_next = tx_desc_next(txdesc_n);
01471
01472
01473 txdesc_n->lmac.hw_desc->thd.nextmpdudesc_ptr = 0;
01474 }
01475
01476
01477 co_list_push_front(&txlist->aggregates, &agg_desc->list_hdr);
01478
01479 return !split;
01480 }
01481 #endif // NX_MAC_HE
01482
01483 #if RW_MUMIMO_TX_EN
01484
01492 static void txl_mumimo_convert(uint8_t ac, uint8_t user_pos)
01493 {
01494 struct txl_list *txlist = &txl_cntrl_env.txlist[ac];
01495 struct txl_mumimo_build_info_tag *mumimo = &txlist->mumimo;
01496 struct txdesc *txdesc = (struct txdesc *)co_list_pick(&mumimo->tx[user_pos]);
01497 struct tx_agg_desc *agg_desc = txdesc->lmac.agg_desc;
01498
01499
01500
01501 txlist->ppdu_cnt++;
01502
01503
01504 if (is_mpdu_agg(txdesc))
01505 {
01506 struct txdesc *last = (struct txdesc *)co_list_pick_last(&mumimo->tx[user_pos]);
01507 struct tx_hd *thd = &last->lmac.hw_desc->thd;
01508
01509
01510 thd->nextmpdudesc_ptr = CPU2HW(&agg_desc->bar_thd);
01511
01512
01513 co_list_push_back(&txlist->aggregates, &agg_desc->list_hdr);
01514 }
01515 else
01516 {
01517
01518 txl_agg_desc_free(agg_desc);
01519
01520
01521 txdesc->lmac.agg_desc = NULL;
01522 }
01523
01524
01525 while (txlist->first_to_download[0] == NULL)
01526 {
01527 if (!txl_payload_alloc(txdesc, ac, 0))
01528 break;
01529
01530 txdesc = tx_desc_next(txdesc);
01531 if (txdesc == NULL)
01532 break;
01533 }
01534
01535 co_list_concat(&txlist->transmitting[0], &mumimo->tx[user_pos]);
01536 }
01537
01551 static uint32_t txl_mumimo_duration_ns(uint32_t length, uint8_t mcs, bool sgi,
01552 uint8_t bw, uint8_t nss)
01553 {
01554
01555 uint32_t duration;
01556
01557
01558 uint32_t ndbps;
01559 uint32_t nes;
01560 uint32_t bit_cnt;
01561
01562
01563 ndbps = ((uint16_t)nss) * VHT_NDBPS[bw][mcs];
01564
01565
01566
01567
01568 if (bw < BW_80MHZ)
01569 {
01570 nes = (ndbps <= 2160) ? 6 : (ndbps <= 4320) ? 12 : 18;
01571 }
01572
01573 else if (bw == BW_80MHZ)
01574 {
01575 if ((nss == 7) && (ndbps == 8190))
01576 {
01577 nes = 36;
01578 }
01579 else if((nss == 7) && (ndbps == 2457))
01580 {
01581 nes = 18;
01582 }
01583 else
01584 {
01585 nes = (ndbps <= 2106) ? 6 :
01586 (ndbps <= 4212) ? 12 :
01587 (ndbps <= 6318) ? 18 :
01588 (ndbps <= 8424) ? 24 :
01589 36;
01590 }
01591 }
01592
01593 else
01594 {
01595 if (((nss == 4) && (ndbps == 9360)) || ((nss == 7) && (ndbps == 9828)))
01596 {
01597 nes = 36;
01598 }
01599 else if ((ndbps == 14040) && ((nss == 5) || (nss == 6)))
01600 {
01601 nes = 48;
01602 }
01603 else if ((nss == 7) && (ndbps == 16380))
01604 {
01605 nes = 54;
01606 }
01607 else
01608 {
01609 nes = (ndbps <= 2106) ? 6 :
01610 (ndbps <= 4212) ? 12 :
01611 (ndbps <= 6318) ? 18 :
01612 (ndbps <= 8424) ? 24 :
01613 (ndbps <= 10530) ? 30 :
01614 (ndbps <= 12636) ? 36 :
01615 (ndbps <= 14742) ? 42 :
01616 (ndbps <= 16848) ? 48 :
01617 (ndbps <= 18720) ? 54 :
01618 72 ;
01619 }
01620 }
01621
01622
01623
01624
01625
01626
01627
01628 bit_cnt = (length << 3) + 16 + nes;
01629 duration = bit_cnt / ndbps;
01630 duration += (duration * ndbps < bit_cnt) ? 1 : 0;
01631
01632
01633 duration *= sgi ? 3600 : 4000;
01634
01635
01636 return (duration);
01637 }
01638
01647 static void txl_mumimo_ampdu_finish(uint8_t ac, uint8_t user_pos)
01648 {
01649 struct txl_list *txlist = &txl_cntrl_env.txlist[ac];
01650 struct txl_agg_build_tag *agg = &txlist->agg[user_pos];
01651 struct tx_agg_desc *agg_desc = agg->desc;
01652 struct txdesc *txdesc = agg->txdesc_last;
01653 uint32_t length;
01654
01655
01656 PROF_AGG_FINISH_AMPDU_SET();
01657 PROF_MU_USER_POS_SET(user_pos);
01658
01659
01660 if (agg->curr_cnt == 1)
01661 {
01662 struct tx_hd *thd = &txdesc->lmac.hw_desc->thd;
01663
01664
01665 txdesc->umac.flags = WHICHDESC_UNFRAGMENTED_MSDU;
01666
01667
01668 thd->nextmpdudesc_ptr = 0;
01669
01670 thd->macctrlinfo2 = WHICHDESC_UNFRAGMENTED_MSDU | INTERRUPT_EN_TX;
01671
01672
01673 length = thd->frmlen;
01674 }
01675 else
01676 {
01677 struct tx_hd *thd = &txdesc->lmac.hw_desc->thd;
01678 struct tx_hd *a_thd = &agg_desc->a_thd;
01679
01680
01681 set_mpdu_pos(txdesc, WHICHDESC_AMPDU_LAST);
01682 #if NX_UMAC_PRESENT
01683 txdesc->lmac.hw_desc->cfm.ampdu_size = agg->curr_cnt;
01684 #endif
01685
01686
01687 thd->macctrlinfo2 = txdesc->umac.flags | INTERRUPT_EN_TX;
01688
01689
01690 agg_desc->status |= AGG_FORMATTED;
01691
01692
01693 length = a_thd->frmlen;
01694 }
01695
01696
01697 txl_fill_bar(agg_desc, txdesc->umac.sn_win, agg_desc->sta_idx, agg_desc->tid, agg->bw);
01698
01699
01700 txlist->mumimo.open &= ~CO_BIT(user_pos);
01701
01702
01703 txlist->mumimo.length[user_pos] = length;
01704
01705
01706 agg->desc = NULL;
01707
01708
01709 PROF_AGG_FINISH_AMPDU_CLR();
01710 }
01711
01728 static int txl_mumimo_check(struct txdesc * txdesc, uint8_t ac, uint8_t *user_pos)
01729 {
01730 int status = SU_PACKET;
01731 uint8_t group_id = get_group_id(txdesc);
01732 struct txl_list *txlist = &txl_cntrl_env.txlist[ac];
01733
01734
01735 if (is_mpdu_agg(txdesc) && is_mumimo_group_id(group_id) &&
01736 bfr_is_calibrated(txdesc->host.staid))
01737 {
01738
01739 status = MU_PACKET;
01740 *user_pos = get_user_pos(txdesc);
01741
01742
01743 if (txlist->mumimo.users)
01744 {
01745
01746 if (group_id != txlist->mumimo.group_id)
01747 {
01748
01749 if (txlist->mumimo.users & CO_BIT(*user_pos))
01750 txl_mumimo_ampdu_finish(ac, *user_pos);
01751 else
01752 txlist->mumimo.open &= ~CO_BIT(*user_pos);
01753
01754
01755 if (txlist->mumimo.open & txlist->mumimo.users)
01756 {
01757
01758
01759 ASSERT_ERR(txlist->mumimo.txdesc[*user_pos] == NULL);
01760 txlist->mumimo.txdesc[*user_pos] = txdesc;
01761 status = MU_PAUSED;
01762 }
01763 else
01764 {
01765
01766 txl_agg_mumimo_close(ac);
01767 return (MU_RESTART_CHECK);
01768 }
01769 }
01770 else
01771 {
01772 txdesc->umac.phy_flags &= VHT_MCS_MASK;
01773 txdesc->umac.phy_flags |= txlist->mumimo.phy_flags;
01774 }
01775 }
01776 else
01777 {
01778
01779 PROF_MU_PPDU_START_SET();
01780 txlist->mumimo.group_id = group_id;
01781
01782 txlist->mumimo.phy_flags = txdesc->umac.phy_flags & ~MCS_INDEX_TX_RCX_MASK;
01783 txdesc->umac.phy_flags &= ~VHT_NSS_MASK;
01784 PROF_MU_PPDU_START_CLR();
01785 }
01786
01787 PROF_MU_USER_POS_SET(*user_pos);
01788 }
01789 else
01790 {
01791
01792 if (txlist->mumimo.users)
01793 {
01794 *user_pos = get_user_pos(txdesc);
01795
01796 if (txlist->mumimo.users & CO_BIT(*user_pos))
01797 txl_mumimo_ampdu_finish(ac, *user_pos);
01798 else
01799 txlist->mumimo.open &= ~CO_BIT(*user_pos);
01800
01801
01802 if (txlist->mumimo.open & txlist->mumimo.users)
01803 {
01804
01805
01806 ASSERT_ERR(txlist->mumimo.txdesc[*user_pos] == NULL);
01807 txlist->mumimo.txdesc[*user_pos] = txdesc;
01808 status = MU_PAUSED;
01809 }
01810 else
01811 {
01812
01813 txl_agg_mumimo_close(ac);
01814 return (MU_RESTART_CHECK);
01815 }
01816 }
01817 else
01818 {
01819 *user_pos = 0;
01820 }
01821 }
01822
01823 return (status);
01824 }
01825
01838 static void txl_mumimo_secondary_done(uint8_t access_category, uint8_t user_idx)
01839 {
01840 struct txl_list *txlist = &txl_cntrl_env.txlist[access_category];
01841
01842
01843 ASSERT_ERR(user_idx != 0);
01844
01845
01846 while (1)
01847 {
01848 struct txdesc *txdesc;
01849 struct tx_hd *txhd;
01850 uint32_t txstatus;
01851 struct tx_agg_desc *agg_desc;
01852
01853
01854 txdesc = (struct txdesc *)co_list_pick(&(txlist->transmitting[user_idx]));
01855
01856
01857 if (txdesc == NULL)
01858 break;
01859
01860 txhd = &txdesc->lmac.hw_desc->thd;
01861 txstatus = txhd->statinfo;
01862 agg_desc = txdesc->lmac.agg_desc;
01863
01864
01865
01866
01867
01868 if (txstatus & DESC_DONE_TX_BIT)
01869 {
01870
01871 PROF_AGG_SMPDU_DONETX_SET();
01872
01873 PROF_MU_USER_POS_IRQ_SET(get_user_pos(txdesc));
01874
01875 #if !NX_FULLY_HOSTED
01876
01877 txl_free_done_mpdu(txdesc, access_category, user_idx);
01878 #endif
01879
01880
01881
01882 txdesc->lmac.hw_desc->cfm.status = txstatus;
01883
01884
01885 PROF_AGG_SMPDU_DONETX_CLR();
01886 }
01887
01888 else
01889 {
01890 #if !NX_FULLY_HOSTED && NX_AMSDU_TX
01891
01892 txl_check_done_amsdu_subframe(txdesc, access_category, user_idx);
01893 #endif
01894 break;
01895 }
01896
01897
01898 co_list_pop_front(&(txlist->transmitting[user_idx]));
01899
01900
01901 txdesc->lmac.hw_desc->cfm.status = txstatus;
01902 co_list_push_back(&agg_desc->cfm, (struct co_list_hdr *)txdesc);
01903 }
01904 }
01905
01906 void txl_agg_mumimo_close(uint8_t ac)
01907 {
01908 struct txl_list *txlist = &txl_cntrl_env.txlist[ac];
01909 struct txl_mumimo_build_info_tag *mumimo = &txlist->mumimo;
01910 int i;
01911 uint32_t dur_max = 0;
01912 uint8_t prim_user_pos = 0;
01913 uint8_t nb_users = 0;
01914 bool mumimook = true;
01915
01916 PROF_MU_PPDU_CLOSE_SET();
01917
01918
01919 for (i = 0; i < RW_USER_MAX; i++)
01920 {
01921 if (mumimo->users & CO_BIT(i))
01922 {
01923 struct txl_agg_build_tag *agg = &txlist->agg[i];
01924 struct txdesc *txdesc = (struct txdesc *)co_list_pick(&mumimo->tx[i]);
01925 uint32_t rate_info = mumimo->rateinfo[i];
01926 uint32_t duration;
01927
01928
01929 if (agg->desc != NULL)
01930 {
01931 txl_mumimo_ampdu_finish(ac, i);
01932 }
01933
01934
01935 if (!is_mpdu_agg(txdesc))
01936 mumimook = false;
01937
01938
01939 duration = txl_mumimo_duration_ns(mumimo->length[i],
01940 (rate_info & VHT_MCS_MASK) >> VHT_MCS_OFT,
01941 (rate_info & SHORT_GI_TX_RCX_MASK) != 0,
01942 (rate_info & BW_TX_RCX_MASK) >> BW_TX_RCX_OFT,
01943 ((rate_info & VHT_NSS_MASK) >> VHT_NSS_OFT) + 1);
01944
01945
01946 if (duration > dur_max)
01947 {
01948
01949
01950 dur_max = duration;
01951 prim_user_pos = i;
01952 }
01953
01954
01955 nb_users++;
01956 }
01957 }
01958
01959
01960 if ((nb_users > 1) && (mumimook))
01961 {
01962 struct txdesc *txdesc = (struct txdesc *)co_list_pick(&mumimo->tx[prim_user_pos]);
01963
01964
01965 if (is_mpdu_agg(txdesc))
01966 {
01967 struct tx_agg_desc *prim_agg_desc = txdesc->lmac.agg_desc;
01968 struct tx_hd *a_thd = &prim_agg_desc->a_thd;
01969 struct tx_hd *bar_thd = &prim_agg_desc->bar_thd;
01970 struct txdesc *last = (struct txdesc *)co_list_pick_last(&mumimo->tx[prim_user_pos]);
01971 struct tx_hd *thd = &last->lmac.hw_desc->thd;
01972 int sec_idx = 1;
01973 uint32_t *sec_user_ptr = &a_thd->sec_user1_ptr;
01974 struct tx_agg_desc *agg_desc = prim_agg_desc;
01975
01976 PROF_MU_USER_POS_SET(prim_user_pos);
01977
01978
01979 thd->nextmpdudesc_ptr = CPU2HW(&prim_agg_desc->bar_thd);
01980
01981
01982 prim_agg_desc->status |= AGG_INT;
01983 prim_agg_desc->download = 0;
01984 prim_agg_desc->prim_agg_desc = prim_agg_desc;
01985
01986
01987 a_thd->phyctrlinfo = (mumimo->group_id << GID_TX_OFT) |
01988 (prim_user_pos << USER_POS_OFT) |
01989 USE_MUMIMO_TX_BIT;
01990
01991
01992 co_list_push_back(&txlist->aggregates, &prim_agg_desc->list_hdr);
01993
01994
01995
01996 txlist->ppdu_cnt++;
01997
01998
01999 for (i = 0; i < RW_USER_MAX; i++)
02000 {
02001 if (mumimo->users & CO_BIT(i))
02002 {
02003 int user_q_idx;
02004 txdesc = (struct txdesc *)co_list_pick(&mumimo->tx[i]);
02005
02006 PROF_MU_USER_POS_SET(i);
02007
02008 if (i != prim_user_pos)
02009 {
02010 agg_desc = txdesc->lmac.agg_desc;
02011
02012
02013 if (is_mpdu_agg(txdesc))
02014 {
02015 thd = &agg_desc->a_thd;
02016
02017
02018 *sec_user_ptr++ = CPU2HW(&agg_desc->a_thd);
02019 }
02020 else
02021 {
02022 thd = &txdesc->lmac.hw_desc->thd;
02023
02024
02025 *sec_user_ptr++ = CPU2HW(&txdesc->lmac.hw_desc->thd);
02026 }
02027
02028
02029 bar_thd->nextfrmexseq_ptr = CPU2HW(&agg_desc->bar_thd);
02030 bar_thd = &agg_desc->bar_thd;
02031
02032
02033 thd->phyctrlinfo = (i << USER_POS_OFT) | USE_MUMIMO_TX_BIT;
02034
02035
02036 user_q_idx = sec_idx++;
02037
02038
02039 agg_desc->prim_agg_desc = prim_agg_desc;
02040 agg_desc->status |= AGG_INT;
02041
02042
02043 co_list_push_back(&txlist->aggregates, &agg_desc->list_hdr);
02044 }
02045 else
02046 {
02047
02048 user_q_idx = 0;
02049 }
02050
02051
02052 prim_agg_desc->download |= CO_BIT(user_q_idx);
02053
02054
02055 while (txlist->first_to_download[user_q_idx] == NULL)
02056 {
02057 if (!txl_payload_alloc(txdesc, ac, user_q_idx))
02058 break;
02059
02060 txdesc = tx_desc_next(txdesc);
02061 if (txdesc == NULL)
02062 break;
02063 }
02064
02065 co_list_concat(&txlist->transmitting[user_q_idx], &mumimo->tx[i]);
02066 }
02067 }
02068
02069 agg_desc->status &= ~AGG_INT;
02070
02071 prim_agg_desc->last_bar_thd = bar_thd;
02072 }
02073 else
02074 {
02075
02076
02077 for (i = 0; i < RW_USER_MAX; i++)
02078 {
02079 if (mumimo->users & CO_BIT(i))
02080 {
02081
02082 txl_mumimo_convert(ac, i);
02083 }
02084 }
02085 }
02086 }
02087 else
02088 {
02089
02090
02091 for (i = 0; i < RW_USER_MAX; i++)
02092 {
02093 if (mumimo->users & CO_BIT(i))
02094 {
02095
02096 txl_mumimo_convert(ac, i);
02097 }
02098 }
02099 }
02100
02101
02102 mumimo->nb_users = 0;
02103 mumimo->users = 0;
02104 mumimo->first_user_pos = (mumimo->first_user_pos + 1) % RW_USER_MAX;
02105 mumimo->open = MU_USER_MASK;
02106
02107
02108 for (i = 0; i < RW_USER_MAX; i++)
02109 {
02110 int pos = (mumimo->first_user_pos + i) % RW_USER_MAX;
02111 struct txdesc *txdesc = mumimo->txdesc[pos];
02112
02113 if (txdesc != NULL)
02114 {
02115 int status;
02116
02117 mumimo->txdesc[pos] = NULL;
02118
02119 status = txl_agg_push_mpdu(txdesc, ac);
02120
02121 if (status == SU_PACKET)
02122 {
02123
02124 if (txlist->first_to_download[0] == NULL)
02125 {
02126 txl_payload_alloc(txdesc, ac, 0);
02127 }
02128 co_list_push_back(&txlist->transmitting[0], &txdesc->list_hdr);
02129 }
02130 }
02131 }
02132
02133
02134 macif_tx_enable_users(ac, mumimo->open);
02135
02136 PROF_MU_PPDU_CLOSE_CLR();
02137 }
02138 #endif // RW_MUMIMO_TX_EN
02139
02151 uint16_t txl_agg_mpdu_nb_delims(struct tx_hd *thd, uint16_t mmss_bytes)
02152 {
02153 uint16_t nb_delims = 0;
02154 uint16_t subfrm_len = txl_mpdu_subframe_len(thd);
02155
02156
02157 if (subfrm_len < mmss_bytes)
02158 {
02159
02160 mmss_bytes -= subfrm_len;
02161
02162
02163 nb_delims = (mmss_bytes + DELIMITER_LEN - 1) / DELIMITER_LEN;
02164 }
02165 return nb_delims;
02166 }
02167
02168 void txl_agg_init(void)
02169 {
02170
02171 txl_agg_hwdesc_init();
02172 }
02173
02174 void txl_agg_reset(void)
02175 {
02176
02177 txl_agg_hwdesc_reset();
02178 }
02179
02180 void txl_agg_finish(uint8_t ac)
02181 {
02182 struct txl_list *txlist = &txl_cntrl_env.txlist[ac];
02183 struct txl_agg_build_tag *agg = &txlist->agg[0];
02184 struct tx_agg_desc *agg_desc = agg->desc;
02185 struct txdesc *txdesc = agg->txdesc_last;
02186
02187
02188 PROF_AGG_FINISH_AMPDU_SET();
02189
02190
02191 if (agg->curr_cnt == 1)
02192 {
02193 struct tx_hd *thd = &txdesc->lmac.hw_desc->thd;
02194 struct txl_buffer_tag *buffer = txl_buffer_get(txdesc);
02195
02196
02197 txdesc->umac.flags = WHICHDESC_UNFRAGMENTED_MSDU;
02198
02199
02200 thd->nextmpdudesc_ptr = 0;
02201
02202 thd->macctrlinfo2 = WHICHDESC_UNFRAGMENTED_MSDU | INTERRUPT_EN_TX;
02203
02204
02205 if (buffer != NULL)
02206 {
02207 struct txl_buffer_control *bufctrl = &buffer->buffer_control;
02208 struct tx_policy_tbl *pol = &bufctrl->policy_tbl;
02209
02210
02211 if (agg_desc->status & AGG_FIRST_DOWNLOADED)
02212 {
02213
02214 thd->phyctrlinfo = bufctrl->phy_control_info;
02215
02216 thd->policyentryaddr = CPU2HW(pol);
02217
02218 thd->macctrlinfo1 = bufctrl->mac_control_info;
02219
02220 #if RW_BFMER_EN
02221 if (bfr_is_enabled() && !bfr_is_bfmed_sglt_allowed(txdesc))
02222 {
02223
02224
02225
02226 pol->phycntrlinfo2 &= ~(BMFED_BIT | SMM_INDEX_PT_MASK);
02227
02228
02229
02230
02231
02232
02233
02234 pol->phycntrlinfo2 |= 2 << SMM_INDEX_PT_OFT;
02235 }
02236 #endif
02237 #if NX_MAC_HE
02238
02239 if (!is_htc_sglt_allowed(txdesc))
02240 txl_buffer_remove_htc(thd);
02241 #endif
02242
02243 #if NX_AMSDU_TX
02244
02245 if (txl_buffer_is_amsdu_multi_buf(txdesc))
02246 {
02247
02248 pol->maccntrlinfo2 &= ~(LONG_RETRY_LIMIT_MASK | SHORT_RETRY_LIMIT_MASK);
02249 }
02250 #endif
02251
02252 #if TRACE_COMPO(LMAC)
02253 {
02254 struct mac_hdr *mac_hdr = (struct mac_hdr *)HW2CPU(txl_buffer_machdr_get(txdesc));
02255 TRACE_LMAC(TX, "{VIF-%d} to STA-%d %fc SN=%d (A-MDPU to singleton)",
02256 txdesc->host.vif_idx, txdesc->host.staid, mac_hdr->fctl,
02257 (mac_hdr->seq >> MAC_SEQCTRL_NUM_OFT));
02258 }
02259 #endif // TRACE_COMPO(LMAC)
02260
02261 #if NX_MAC_HE
02262
02263 txl_he_txop_dur_rtscts_thres_mpdu_check(txdesc);
02264 #endif
02265
02266
02267 txl_frame_exchange_chain(thd, thd, ac);
02268 }
02269 }
02270
02271 txl_agg_desc_free(agg_desc);
02272
02273
02274 txdesc->lmac.agg_desc = NULL;
02275 }
02276 else
02277 {
02278 struct tx_hd *thd = &txdesc->lmac.hw_desc->thd;
02279 struct txl_buffer_tag *buffer = txl_buffer_get(txdesc);
02280 #if NX_UMAC_PRESENT
02281 struct tx_cfm_tag *cfm = txl_cfm_tag_get(txdesc);
02282 #endif
02283
02284
02285 set_mpdu_pos(txdesc, WHICHDESC_AMPDU_LAST);
02286
02287 #if NX_MAC_HE
02288 agg_desc->txdesc_last = txdesc;
02289 txl_he_txop_dur_rtscts_thres_ampdu_check(agg->txdesc_first);
02290 #endif
02291
02292 #if NX_UMAC_PRESENT
02293 cfm->ampdu_size = agg->curr_cnt;
02294 #endif
02295
02296
02297 txl_fill_bar(agg_desc, txdesc->umac.sn_win, agg_desc->sta_idx, agg_desc->tid, agg->bw);
02298
02299
02300 thd->nextmpdudesc_ptr = CPU2HW(&agg_desc->bar_thd);
02301
02302
02303 thd->macctrlinfo2 = txdesc->umac.flags | INTERRUPT_EN_TX;
02304
02305
02306 agg_desc->status |= AGG_FORMATTED;
02307
02308
02309
02310 if (buffer != NULL)
02311 {
02312
02313 if (!(agg_desc->status & AGG_ALLOC))
02314 {
02315
02316 if (!(agg_desc->status & AGG_FIRST_DOWNLOADED))
02317 {
02318
02319
02320 struct txl_buffer_tag *buffer_first = txl_buffer_get(agg->txdesc_first);
02321 buffer_first->flags |= BUF_ALLOC_OK;
02322 }
02323 else
02324
02325
02326 agg_desc->status |= AGG_DOWNLOADED;
02327 }
02328 }
02329
02330
02331 if (agg_desc->status & AGG_DOWNLOADED)
02332 {
02333 struct tx_hd *next_prev_hd = &agg_desc->bar_thd;
02334 #if NX_MAC_HE
02335
02336
02337 struct tx_policy_tbl *pt = HW2CPU(agg_desc->a_thd.policyentryaddr);
02338 pt->ratecntrlinfo[0] = agg->txdesc_first->umac.phy_flags;
02339 #endif
02340
02341 #if TRACE_COMPO(LMAC)
02342 struct tx_hd *first_thb = (struct tx_hd *)HW2CPU(agg_desc->a_thd.nextmpdudesc_ptr);
02343 struct tx_pbd *first_pbd = (struct tx_pbd *)HW2CPU(first_thb->first_pbd_ptr);
02344 struct mac_hdr *mac_hdr = (struct mac_hdr *)HW2CPU(first_pbd->datastartptr);
02345 TRACE_LMAC(TX, "[AC %d] {VIF-%d} to STA-%d AMPDU (#%d, %lu bytes) SN=%d",
02346 ac, txdesc->host.vif_idx, txdesc->host.staid, agg->curr_cnt,
02347 TR_32(agg_desc->a_thd.frmlen), (mac_hdr->seq >> MAC_SEQCTRL_NUM_OFT));
02348 #endif // TRACE_COMPO(LMAC)
02349
02350
02351 txl_frame_exchange_chain(&agg_desc->a_thd, next_prev_hd, ac);
02352 }
02353
02354
02355 co_list_push_back(&txl_cntrl_env.txlist[ac].aggregates, &agg_desc->list_hdr);
02356 }
02357
02358
02359
02360 txl_cntrl_env.txlist[ac].ppdu_cnt++;
02361
02362
02363 agg->desc = NULL;
02364
02365
02366 PROF_AGG_FINISH_AMPDU_CLR();
02367 }
02368
02369 int txl_agg_push_mpdu(struct txdesc * txdesc, uint8_t ac)
02370 {
02371 struct tx_hd *thd = &txdesc->lmac.hw_desc->thd;
02372 uint8_t user_pos = 0;
02373 int status = SU_PACKET;
02374
02375
02376 uint8_t tid = txdesc->host.tid;
02377 uint8_t staid = txdesc->host.staid;
02378
02379 do
02380 {
02381 struct txl_list *txlist = &txl_cntrl_env.txlist[ac];
02382 struct txl_agg_build_tag *agg;
02383
02384 #if RW_MUMIMO_TX_EN
02385 status = txl_mumimo_check(txdesc, ac, &user_pos);
02386
02387
02388 if (status == MU_PAUSED)
02389 break;
02390
02391
02392 if (status == MU_RESTART_CHECK)
02393 continue;
02394 #endif
02395
02396
02397 agg = &txlist->agg[user_pos];
02398
02399
02400 if (agg->desc == NULL)
02401 {
02402
02403
02404 if (!is_mpdu_agg(txdesc)
02405 #if NX_UMAC_PRESENT
02406 || !txl_ampdu_has_ht_vht_rate(txdesc)
02407 #endif
02408 )
02409 {
02410
02411
02412 txl_cntrl_env.txlist[ac].ppdu_cnt++;
02413 break;
02414 }
02415
02416
02417 agg->desc = txl_agg_desc_alloc(ac);
02418
02419
02420 if (agg->desc == NULL)
02421 {
02422 #if RW_MUMIMO_TX_EN
02423
02424
02425 if (txlist->mumimo.users)
02426 {
02427 txl_agg_mumimo_close(ac);
02428 }
02429
02430
02431 status = SU_PACKET;
02432 #endif
02433
02434 txdesc->umac.flags = WHICHDESC_UNFRAGMENTED_MSDU;
02435
02436
02437 txl_cntrl_env.txlist[ac].ppdu_cnt++;
02438 break;
02439 }
02440
02441
02442 PROF_AGG_START_AMPDU_SET();
02443
02444
02445 agg->desc->status = 0;
02446 agg->desc->available_len = 0;
02447 agg->desc->available_cnt = 0;
02448 agg->desc->sta_idx = staid;
02449 agg->desc->tid = tid;
02450 agg->desc->user_cnt = 1;
02451 #if RW_MUMIMO_TX_EN
02452 agg->desc->download = 0;
02453 agg->desc->prim_agg_desc = NULL;
02454 agg->desc->last_bar_thd = NULL;
02455 co_list_init(&agg->desc->cfm);
02456 #endif
02457
02458
02459
02460 txl_ampdu_constraints_get(txdesc, ac, agg);
02461
02462
02463 PROF_AGG_START_AMPDU_CLR();
02464
02465
02466 PROF_AGG_ADD_MPDU_SET();
02467
02468
02469 agg->desc->a_thd.frmlen = txl_mpdu_subframe_len(thd);
02470
02471 agg->desc->a_thd.statinfo = 0;
02472 agg->desc->a_thd.nextmpdudesc_ptr = CPU2HW(thd);
02473 agg->desc->a_thd.first_pbd_ptr = 0;
02474 agg->desc->a_thd.optlen[0] = 0;
02475 agg->desc->a_thd.optlen[1] = 0;
02476 agg->desc->a_thd.optlen[2] = 0;
02477
02478
02479 agg->curr_cnt = 1;
02480
02481
02482 agg->nb_delims = txl_agg_mpdu_nb_delims(thd, agg->mmss_bytes);
02483 #if NX_MAC_HE
02484
02485 txdesc->umac.flags |= (agg->nb_delims << NB_BLANK_DELIM_OFT);
02486 agg->desc->a_thd.frmlen += agg->nb_delims * DELIMITER_LEN;
02487 #endif
02488
02489
02490 agg->txdesc_last = txdesc;
02491 agg->txdesc_first = txdesc;
02492
02493
02494 set_mpdu_pos(txdesc, WHICHDESC_AMPDU_FIRST);
02495
02496
02497 txdesc->lmac.agg_desc = agg->desc;
02498 txdesc->umac.flags |= UNDER_BA_SETUP_BIT;
02499
02500
02501 thd->macctrlinfo2 = txdesc->umac.flags;
02502
02503 #if RW_MUMIMO_TX_EN
02504 if (status == MU_PACKET)
02505 {
02506 PROF_MU_MPDU_ADD_SET();
02507 co_list_push_back(&txlist->mumimo.tx[user_pos], &txdesc->list_hdr);
02508
02509 txlist->mumimo.users |= CO_BIT(user_pos);
02510 txlist->mumimo.rateinfo[user_pos] = txdesc->umac.phy_flags;
02511 agg->desc->status |= AGG_MU;
02512 PROF_MU_MPDU_ADD_CLR();
02513 }
02514 #endif
02515
02516
02517 PROF_AGG_ADD_MPDU_CLR();
02518 break;
02519 }
02520 else
02521 {
02522 struct tx_agg_desc *agg_desc = agg->desc;
02523 struct tx_hd *a_thd = &agg_desc->a_thd;
02524 struct tx_hd *prev_thd = &agg->txdesc_last->lmac.hw_desc->thd;
02525 uint32_t ampdu_subfrmlen;
02526 #if NX_BW_LEN_ADAPT
02527 uint8_t bw_idx = agg->bw_idx;
02528 #else
02529 uint8_t bw_idx = 0;
02530 #endif
02531
02532
02533 if (!txl_desc_is_agg(txdesc, agg_desc))
02534 {
02535 #if RW_MUMIMO_TX_EN
02536
02537 if (agg_desc->status & AGG_MU)
02538 {
02539 MU_AMPDU_CLOSE();
02540 }
02541 else
02542 {
02543 #endif
02544
02545 txl_agg_finish(ac);
02546
02547
02548 continue;
02549 #if RW_MUMIMO_TX_EN
02550 }
02551 #endif
02552 }
02553
02554 #if NX_MAC_HE
02555 agg->nb_delims = txl_agg_mpdu_nb_delims(thd, agg->mmss_bytes);
02556 #endif
02557
02558
02559 ampdu_subfrmlen = txl_mpdu_subframe_len(thd) + agg->nb_delims * DELIMITER_LEN;
02560
02561
02562 if ((ampdu_subfrmlen + a_thd->frmlen) > agg->max_len[bw_idx])
02563 {
02564 #if NX_BW_LEN_ADAPT
02565 if (bw_idx < agg->bw)
02566 {
02567
02568
02569
02570
02571
02572 if ((agg->curr_cnt == 1)
02573 || ((ampdu_subfrmlen + a_thd->frmlen) > agg->max_len[bw_idx+1]))
02574 {
02575 #if RW_MUMIMO_TX_EN
02576
02577 if (agg_desc->status & AGG_MU)
02578 {
02579 MU_AMPDU_CLOSE();
02580 }
02581 else
02582 {
02583 #endif
02584
02585 txl_agg_finish(ac);
02586
02587 continue;
02588 #if RW_MUMIMO_TX_EN
02589 }
02590 #endif
02591 }
02592
02593
02594 PROF_BW_DROP_STEP_SET();
02595
02596
02597 agg_desc->txdesc[bw_idx] = agg->txdesc_last;
02598
02599
02600 a_thd->optlen[bw_idx] = a_thd->frmlen;
02601
02602
02603 agg->bw_idx++;
02604
02605
02606 PROF_BW_DROP_STEP_CLR();
02607 }
02608 else
02609 #endif
02610 {
02611
02612 #if RW_MUMIMO_TX_EN
02613
02614 if (agg_desc->status & AGG_MU)
02615 {
02616 MU_AMPDU_CLOSE();
02617 }
02618 else
02619 {
02620 #endif
02621
02622 txl_agg_finish(ac);
02623
02624 continue;
02625 #if RW_MUMIMO_TX_EN
02626 }
02627 #endif
02628 }
02629 }
02630
02631
02632 PROF_AGG_ADD_MPDU_SET();
02633
02634 #if RW_MUMIMO_TX_EN
02635
02636 if (!(agg_desc->status & AGG_MU))
02637 {
02638 status = SU_PACKET;
02639 }
02640 #endif
02641
02642
02643 txdesc->lmac.agg_desc = agg_desc;
02644
02645
02646 txdesc->umac.flags |= (agg->nb_delims << NB_BLANK_DELIM_OFT) | UNDER_BA_SETUP_BIT;
02647
02648
02649 set_mpdu_pos(txdesc, WHICHDESC_AMPDU_INT);
02650
02651
02652 thd->macctrlinfo2 = txdesc->umac.flags;
02653
02654
02655 prev_thd->nextmpdudesc_ptr = CPU2HW(thd);
02656
02657
02658 a_thd->frmlen += ampdu_subfrmlen;
02659
02660 #if !NX_MAC_HE
02661
02662 agg->nb_delims = txl_agg_mpdu_nb_delims(thd, agg->mmss_bytes);
02663 #endif
02664
02665
02666 agg->txdesc_last = txdesc;
02667
02668 #if RW_MUMIMO_TX_EN
02669 if (status == MU_PACKET)
02670 {
02671 PROF_MU_MPDU_ADD_SET();
02672 co_list_push_back(&txlist->mumimo.tx[user_pos], &txdesc->list_hdr);
02673 PROF_MU_MPDU_ADD_CLR();
02674 }
02675 #endif
02676
02677
02678 PROF_AGG_ADD_MPDU_CLR();
02679
02680
02681 agg->curr_cnt++;
02682
02683
02684 if (agg->curr_cnt >= agg->max_cnt)
02685 {
02686
02687 #if RW_MUMIMO_TX_EN
02688 if (status == MU_PACKET)
02689 {
02690 txl_mumimo_ampdu_finish(ac, user_pos);
02691
02692 if (txlist->mumimo.open & txlist->mumimo.users)
02693 {
02694
02695
02696 status = MU_PAUSED;
02697 }
02698 else
02699 {
02700
02701 txl_agg_mumimo_close(ac);
02702 }
02703 }
02704 else
02705 #endif
02706 txl_agg_finish(ac);
02707 }
02708
02709
02710 break;
02711 }
02712 } while (1);
02713
02714 return (status);
02715 }
02716
02717
02718 void txl_agg_release(struct tx_agg_desc *agg_desc)
02719 {
02720
02721 agg_desc->user_cnt--;
02722
02723
02724 if (agg_desc->user_cnt == 0)
02725 {
02726 txl_agg_desc_free(agg_desc);
02727 }
02728 }
02729 struct tx_hd *txl_agg_change_to_singleton(struct txdesc *txdesc, bool he_tb)
02730 {
02731 struct tx_hd *thd = &txdesc->lmac.hw_desc->thd;
02732 struct txl_buffer_tag *buffer = txl_buffer_get(txdesc);
02733
02734
02735 txdesc->umac.flags = WHICHDESC_UNFRAGMENTED_MSDU;
02736
02737
02738 txdesc->lmac.agg_desc = NULL;
02739
02740
02741 thd->nextmpdudesc_ptr = 0;
02742
02743
02744 thd->macctrlinfo2 = WHICHDESC_UNFRAGMENTED_MSDU | INTERRUPT_EN_TX;
02745
02746 if (buffer)
02747 {
02748 struct txl_buffer_control *bufctrl = &buffer->buffer_control;
02749
02750 #if NX_UMAC_PRESENT
02751
02752 txl_buffer_control_copy(txdesc, buffer);
02753 #if NX_MAC_HE
02754
02755 if (!he_tb && !is_htc_sglt_allowed(txdesc))
02756 txl_buffer_remove_htc(thd);
02757 #endif
02758 #endif
02759
02760 #if NX_MAC_HE
02761
02762 buffer->flags |= BUF_SINGLETON_READY;
02763
02764 txl_he_txop_dur_rtscts_thres_mpdu_check(txdesc);
02765 #endif
02766
02767
02768 thd->macctrlinfo1 = bufctrl->mac_control_info;
02769
02770 thd->phyctrlinfo = bufctrl->phy_control_info;
02771
02772 thd->policyentryaddr = CPU2HW(&bufctrl->policy_tbl);
02773 #if NX_AMSDU_TX
02774
02775 if (txl_buffer_is_amsdu_multi_buf(txdesc))
02776 {
02777 struct tx_policy_tbl *pol = &bufctrl->policy_tbl;
02778
02779
02780 pol->maccntrlinfo2 &= ~(LONG_RETRY_LIMIT_MASK | SHORT_RETRY_LIMIT_MASK);
02781 }
02782 #endif
02783
02784 return (thd);
02785 }
02786
02787 return NULL;
02788 }
02789
02790 #if (NX_BW_LEN_ADAPT)
02791 void txl_agg_bw_drop_handle(uint8_t access_category)
02792 {
02793 struct txl_list *txlist = &txl_cntrl_env.txlist[access_category];
02794 struct txdesc * txdesc = (struct txdesc *)co_list_pick(&(txlist->transmitting[0]));
02795 struct tx_agg_desc *agg_desc;
02796 struct tx_hd *thd, *prev_thd, *next_thd;
02797 uint8_t bw;
02798
02799
02800 ASSERT_ERR(txdesc != NULL);
02801
02802
02803 while (!is_mpdu_agg(txdesc))
02804 {
02805 struct tx_hd *txhd = &txdesc->lmac.hw_desc->thd;
02806 uint32_t txstatus = txhd->statinfo;
02807 if (!(txstatus & DESC_DONE_TX_BIT))
02808 return;
02809 txdesc = tx_desc_next(txdesc);
02810
02811 if (txdesc == NULL)
02812 return;
02813 }
02814
02815
02816 ASSERT_ERR(is_mpdu_first(txdesc));
02817
02818
02819 agg_desc = txdesc->lmac.agg_desc;
02820
02821
02822 bw = nxmac_tx_bw_after_drop_getf();
02823 txdesc = agg_desc->txdesc[bw];
02824 thd = &txdesc->lmac.hw_desc->thd;
02825
02826 ASSERT_ERR(!is_mpdu_last(txdesc));
02827
02828
02829
02830 set_mpdu_pos(txdesc, WHICHDESC_AMPDU_LAST);
02831
02832
02833 thd->nextmpdudesc_ptr = CPU2HW(&agg_desc->bar_thd);
02834
02835
02836 thd->macctrlinfo2 = txdesc->umac.flags | INTERRUPT_EN_TX;
02837
02838 prev_thd = &agg_desc->bar_thd;
02839 next_thd = HW2CPU(agg_desc->bar_thd.nextfrmexseq_ptr);
02840
02841
02842 txdesc = tx_desc_next(txdesc);
02843 ASSERT_ERR(txdesc != NULL);
02844 while (1)
02845 {
02846 bool last = false;
02847
02848 if (is_mpdu_last(txdesc))
02849 last = true;
02850
02851
02852 txlist->ppdu_cnt++;
02853
02854
02855 thd = txl_agg_change_to_singleton(txdesc, false);
02856
02857 if (thd)
02858 {
02859 prev_thd->nextfrmexseq_ptr = CPU2HW(thd);
02860
02861 if (txl_cntrl_env.txlist[access_category].last_frame_exch == prev_thd)
02862 txl_cntrl_env.txlist[access_category].last_frame_exch = thd;
02863
02864 prev_thd = thd;
02865 }
02866
02867 if (last)
02868 {
02869 thd->nextfrmexseq_ptr = CPU2HW(next_thd);
02870 break;
02871 }
02872
02873 txdesc = tx_desc_next(txdesc);
02874 ASSERT_ERR(txdesc != NULL);
02875 }
02876 }
02877 #endif
02878
02879 void txl_agg_check(uint8_t access_category)
02880 {
02881 struct txl_list *txlist = &txl_cntrl_env.txlist[access_category];
02882 GLOBAL_INT_DISABLE();
02883 if (txlist->ppdu_cnt == 0)
02884 {
02885 #if RW_MUMIMO_TX_EN
02886
02887 if (txlist->mumimo.users)
02888 {
02889 txl_agg_mumimo_close(access_category);
02890 }
02891 else
02892 #endif
02893 if (txlist->agg[0].desc != NULL)
02894 {
02895
02896 txl_agg_finish(access_category);
02897 }
02898 }
02899 GLOBAL_INT_RESTORE();
02900 }
02901
02902
02903 #if RW_MUMIMO_TX_EN
02904 void txl_agg_sec_transmit_trigger(void)
02905 {
02906
02907 PROF_MU_SEC_USER_IRQ_SET();
02908
02909 while (nxmac_sec_users_tx_int_event_get() & TX_SEC_IRQ_BITS)
02910 {
02911 uint8_t access_category;
02912 uint8_t user_idx;
02913 uint8_t highest;
02914 uint32_t status = nxmac_sec_users_tx_int_event_get() & TX_SEC_IRQ_BITS;
02915
02916
02917 ASSERT_REC(status != 0);
02918
02919
02920
02921 status |= status >> (NXMAC_SEC_U_1AC_0_TX_BUF_TRIGGER_POS - NXMAC_SEC_U_1AC_0_TX_TRIGGER_POS);
02922
02923
02924 status &= TX_SEC_IRQ_BITS_MERGED;
02925
02926
02927 highest = 31 - co_clz(status);
02928
02929
02930 access_category = highest % 4;
02931 user_idx = highest / 8;
02932
02933
02934 ASSERT_ERR(access_category < NX_TXQ_CNT);
02935 ASSERT_ERR(user_idx < RW_USER_MAX);
02936
02937
02938 nxmac_sec_users_tx_int_event_clear(CO_BIT(user_idx*8 + access_category + NXMAC_SEC_U_1AC_0_TX_BUF_TRIGGER_POS) |
02939 CO_BIT(user_idx*8 + access_category + NXMAC_SEC_U_1AC_0_TX_TRIGGER_POS));
02940
02941
02942 PROF_TX_AC_IRQ_SET(access_category);
02943
02944
02945 txl_mumimo_secondary_done(access_category, user_idx + 1);
02946 }
02947
02948
02949 PROF_MU_SEC_USER_IRQ_CLR();
02950 }
02951 #endif
02952
02953 void txl_agg_set_ampdu_protection(uint32_t *rc)
02954 {
02955 uint8_t bw, rate, mcs;
02956 uint32_t rc_loc = *rc;
02957
02958
02959
02960 if ((rc_loc & PROT_FRM_EX_RCX_MASK) != PROT_NO_PROT)
02961 return;
02962
02963
02964 bw = (rc_loc & BW_TX_RCX_MASK) >> BW_TX_RCX_OFT;
02965 mcs = ((rc_loc & FORMAT_MOD_TX_RCX_MASK) >> FORMAT_MOD_TX_RCX_OFT) >= FORMATMOD_VHT ?
02966 rc_loc & VHT_MCS_MASK : rc_loc & HT_MCS_MASK;
02967 rate = mcs > 2 ? HW_RATE_24MBPS : HW_RATE_6MBPS;
02968 rc_loc &= ~(PROT_FRM_EX_RCX_MASK | MCS_INDEX_PROT_TX_RCX_MASK | BW_PROT_TX_RCX_MASK |
02969 FORMAT_MOD_PROT_TX_RCX_MASK);
02970 rc_loc |= (bw << BW_PROT_TX_RCX_OFT) | (rate << MCS_INDEX_PROT_TX_RCX_OFT) | PROT_SELF_CTS;
02971 rc_loc |= FORMATMOD_NON_HT_DUP_OFDM << FORMAT_MOD_PROT_TX_RCX_OFT;
02972
02973 *rc = rc_loc;
02974 }
02975
02976 void txl_agg_check_rtscts_retry_limit(struct tx_hd *a_thd, uint8_t access_category)
02977 {
02978 uint32_t a_thd_status = a_thd->statinfo;
02979
02980
02981 if (a_thd_status & DESC_DONE_TX_BIT)
02982 {
02983 struct tx_policy_tbl *pol = HW2CPU(a_thd->policyentryaddr);
02984
02985
02986
02987 ASSERT_REC(a_thd_status & RETRY_LIMIT_REACHED_BIT);
02988
02989
02990 a_thd->statinfo = 0;
02991
02992
02993
02994 pol->ratecntrlinfo[0] &= ~PROT_FRM_EX_RCX_MASK;
02995 pol->ratecntrlinfo[0] |= PROT_SELF_CTS;
02996
02997
02998 txl_cntrl_newhead(CPU2HW(a_thd), access_category);
02999 }
03000 }
03001
03002 void txl_agg_check_saved_agg_desc(uint8_t access_category)
03003 {
03004 struct txl_list *txlist = &txl_cntrl_env.txlist[access_category];
03005 struct tx_agg_desc *agg_desc_prev = txlist->agg_desc_prev;
03006
03007
03008 if (agg_desc_prev != NULL)
03009 {
03010
03011 agg_desc_prev->user_cnt--;
03012
03013
03014 if (agg_desc_prev->user_cnt == 0)
03015 {
03016 txl_agg_desc_free(agg_desc_prev);
03017 }
03018
03019
03020 txlist->agg_desc_prev = NULL;
03021 }
03022 }
03023
03024 #if NX_MAC_HE
03025 struct tx_hd *txl_agg_set_new_ampdu_head(struct txdesc *txdesc, struct tx_hd **bar_thd)
03026 {
03027 struct tx_hd *thd = &txdesc->lmac.hw_desc->thd;
03028 struct tx_agg_desc *agg_desc = txdesc->lmac.agg_desc;
03029 struct txl_buffer_tag *buffer = txl_buffer_get(txdesc);
03030
03031 thd = &agg_desc->a_thd;
03032
03033
03034 thd->nextmpdudesc_ptr = CPU2HW(&txdesc->lmac.hw_desc->thd);
03035 thd->policyentryaddr = CPU2HW(&agg_desc->pol_tbl);
03036 set_mpdu_pos(txdesc, WHICHDESC_AMPDU_FIRST);
03037 txdesc->lmac.hw_desc->thd.macctrlinfo2 &= ~WHICHDESC_MSK;
03038 txdesc->lmac.hw_desc->thd.macctrlinfo2 |= WHICHDESC_AMPDU_FIRST;
03039
03040 if (buffer == NULL)
03041 {
03042 agg_desc->status = AGG_FORMATTED;
03043 agg_desc->available_len = 0;
03044 return NULL;
03045 }
03046
03047 *bar_thd = &agg_desc->bar_thd;
03048 return thd;
03049 }
03050
03051 struct tx_hd *txl_agg_he_tb_prep(struct txdesc *txdesc, struct txdesc **txdesc_next,
03052 uint32_t max_len, uint16_t min_mpdu_len, uint8_t ac)
03053 {
03054 struct tx_agg_desc *agg_desc;
03055 struct tx_hd *thd = &txdesc->lmac.hw_desc->thd;
03056 struct txl_list *txlist = &txl_cntrl_env.txlist[ac];
03057
03058
03059 if (is_mpdu_agg(txdesc))
03060 {
03061
03062
03063 agg_desc = txdesc->lmac.agg_desc;
03064 if (!is_mpdu_first(txdesc) ||
03065 ((agg_desc->status & (AGG_FORMATTED | AGG_DOWNLOADED)) !=
03066 (AGG_FORMATTED | AGG_DOWNLOADED)))
03067 return NULL;
03068
03069
03070 if (agg_desc->a_thd.frmlen > max_len)
03071
03072 return txl_agg_split(txdesc, txdesc_next, max_len, min_mpdu_len, ac);
03073
03074
03075 txl_agg_set_uph(txdesc);
03076
03077 *txdesc_next = tx_desc_next(agg_desc->txdesc_last);
03078 }
03079 else
03080 {
03081
03082
03083 struct txl_buffer_tag *buffer = txl_buffer_get(txdesc);
03084 if (!buffer || !(buffer->flags & BUF_SINGLETON_READY))
03085 return NULL;
03086
03087
03088 if (!txl_agg_is_int_or_mgt(txdesc))
03089 txl_buffer_add_htc(thd);
03090
03091
03092 if (thd->frmlen > max_len)
03093 {
03094
03095 txl_he_mu_edca_blocked(thd, ac);
03096 return NULL;
03097 }
03098
03099
03100 if (!txl_agg_is_int_or_mgt(txdesc))
03101 txl_buffer_update_htc(thd, txl_he_tb_uph_get());
03102
03103 *txdesc_next = tx_desc_next(txdesc);
03104 }
03105
03106
03107
03108 while (*txdesc_next)
03109 {
03110 struct txdesc *txdesc_n = *txdesc_next;
03111
03112
03113
03114 if (txl_agg_is_int_or_mgt(txdesc) || txl_agg_is_int_or_mgt(txdesc_n) ||
03115 (nxmac_tx_hetb_rem_dur_getf() < TX_HE_TB_PROG_TIME))
03116 break;
03117
03118 if (is_mpdu_agg(txdesc))
03119 {
03120 if (!is_mpdu_agg(txdesc_n))
03121 {
03122 if (!txl_agg_he_tb_cat_ampdu_mpdu(txdesc, txdesc_next, max_len, min_mpdu_len, ac))
03123 break;
03124 }
03125 else if (!txl_agg_he_tb_cat_ampdu(txdesc, txdesc_next, max_len, min_mpdu_len, ac))
03126 break;
03127 }
03128 else if (!is_mpdu_agg(txdesc_n) ||
03129 !txl_agg_he_tb_cat_mpdu_ampdu(txdesc, txdesc_next, max_len, min_mpdu_len, ac))
03130 break;
03131 };
03132
03133
03134 if (is_mpdu_agg(txdesc))
03135 {
03136 thd = &txdesc->lmac.agg_desc->a_thd;
03137
03138 txdesc->lmac.agg_desc->txdesc_last->lmac.hw_desc->thd.nextmpdudesc_ptr = 0;
03139 return thd;
03140 }
03141
03142
03143
03144
03145 if (txdesc->lmac.agg_desc)
03146 return thd;
03147
03148
03149 agg_desc = txl_agg_desc_alloc(TX_HE_TB_AMPDU_QUEUE_IDX);
03150 ASSERT_ERR(agg_desc != NULL);
03151
03152
03153 agg_desc->status = 0;
03154 agg_desc->user_cnt = 1;
03155
03156
03157 txdesc->lmac.agg_desc = agg_desc;
03158
03159
03160 co_list_push_front(&txlist->aggregates, &agg_desc->list_hdr);
03161
03162 return thd;
03163 }
03164 #endif // NX_MAC_HE
03165
03166
03167 #endif
03168
03169