- Main Page
- Modules
- Data Structures
- Files

- File List
- Globals

# /space/home/slher/rel/Beken/v6_4_5/macsw/ip/lmac/src/tx/txl/txl_he.c

Go to the documentation of this file.

    00001
    00020 /*
    00021  * INCLUDE FILES
    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 #include "tx_swdesc.h"
    00036 #include "txl_he.h"
    00037 #include "txl_cfm.h"
    00038 #include "txl_agg.h"
    00039 #include "txl_cntrl.h"
    00040 #include "rxl_cntrl.h"
    00041 #include "reg_mac_pl.h"
    00042 #include "reg_mac_core.h"
    00043 #include "dbg.h"
    00044 #include "sta_mgmt.h"
    00045 #include "vif_mgmt.h"
    00046
    00047
    00048 #if NX_MAC_HE
    00049
    00050 /*
    00051  * DEFINES
    00052  ****************************************************************************************
    00053  */
    00059 static const uint16_t TX_HE_RATE_TO_MIN_SEP[12*2*3] =
    00060 {
    00061     //BW20/40,GI0.8us    BW20/40,GI1.6us      BW20/40,GI3.2us    MCS Index
    00062     [  0] =  2,          [  1] =  2,          [  2] =  1,        // MCS 0
    00063     [  6] =  3,          [  7] =  3,          [  8] =  2,        // MCS 1
    00064     [ 12] =  4,          [ 13] =  4,          [ 14] =  3,        // MCS 2
    00065     [ 18] =  5,          [ 19] =  5,          [ 20] =  4,        // MCS 3
    00066     [ 24] =  7,          [ 25] =  7,          [ 26] =  6,        // MCS 4
    00067     [ 30] =  9,          [ 31] =  9,          [ 32] =  8,        // MCS 5
    00068     [ 36] = 10,          [ 37] = 10,          [ 38] =  9,        // MCS 6
    00069     [ 42] = 11,          [ 43] = 11,          [ 44] = 10,        // MCS 7
    00070     [ 48] = 13,          [ 49] = 13,          [ 50] = 11,        // MCS 8
    00071     [ 54] = 15,          [ 55] = 14,          [ 56] = 13,        // MCS 9
    00072     [ 60] = 17,          [ 61] = 16,          [ 62] = 14,        // MCS 10
    00073     [ 66] = 18,          [ 67] = 17,          [ 68] = 16,        // MCS 11
    00074     //BW80/160,GI0.8us   BW80/160,GI1.6us     BW80/160,GI3.2us   MCS Index
    00075     [  3] =  5,          [  4] =  5,          [  5] =  4,        // MCS 0
    00076     [  9] = 10,          [ 10] =  9,          [ 11] =  8,        // MCS 1
    00077     [ 15] = 14,          [ 16] = 13,          [ 17] = 12,        // MCS 2
    00078     [ 21] = 19,          [ 22] = 18,          [ 23] = 16,        // MCS 3
    00079     [ 27] = 28,          [ 28] = 26,          [ 29] = 23,        // MCS 4
    00080     [ 33] = 37,          [ 34] = 35,          [ 35] = 31,        // MCS 5
    00081     [ 39] = 41,          [ 40] = 39,          [ 41] = 35,        // MCS 6
    00082     [ 45] = 46,          [ 46] = 43,          [ 47] = 39,        // MCS 7
    00083     [ 51] = 55,          [ 52] = 52,          [ 53] = 46,        // MCS 8
    00084     [ 57] = 61,          [ 58] = 57,          [ 59] = 52,        // MCS 9
    00085     [ 63] = 68,          [ 64] = 64,          [ 65] = 58,        // MCS 10
    00086     [ 69] = 76,          [ 70] = 71,          [ 71] = 64,        // MCS 11
    00087 };
    00088
    00093 static const uint16_t TX_HE_RATE_TO_32US_LEN[12*2*3] =
    00094 {
    00095     //BW20/40,GI0.8us    BW20/40,GI1.6us      BW20/40,GI3.2us    MCS Index
    00096     [  0] =   34,        [  1] =   32,        [  2] =   29,      // MCS 0
    00097     [  6] =   68,        [  7] =   65,        [  8] =   58,      // MCS 1
    00098     [ 12] =  103,        [ 13] =   97,        [ 14] =   87,      // MCS 2
    00099     [ 18] =  137,        [ 19] =  130,        [ 20] =  117,      // MCS 3
    00100     [ 24] =  206,        [ 25] =  195,        [ 26] =  175,      // MCS 4
    00101     [ 30] =  275,        [ 31] =  260,        [ 32] =  234,      // MCS 5
    00102     [ 36] =  309,        [ 37] =  292,        [ 38] =  263,      // MCS 6
    00103     [ 42] =  344,        [ 43] =  325,        [ 44] =  292,      // MCS 7
    00104     [ 48] =  412,        [ 49] =  390,        [ 50] =  351,      // MCS 8
    00105     [ 54] =  458,        [ 55] =  433,        [ 56] =  390,      // MCS 9
    00106     [ 60] =  516,        [ 61] =  487,        [ 62] =  438,      // MCS 10
    00107     [ 66] =  573,        [ 67] =  541,        [ 68] =  487,      // MCS 11
    00108     //BW80/160,GI0.8us   BW80/160,GI1.6us     BW80/160,GI3.2us   MCS Index
    00109     [  3] =  144,        [  4] =  136,        [  5] =  122,      // MCS 0
    00110     [  9] =  288,        [ 10] =  272,        [ 11] =  245,      // MCS 1
    00111     [ 15] =  432,        [ 16] =  408,        [ 17] =  367,      // MCS 2
    00112     [ 21] =  576,        [ 22] =  544,        [ 23] =  490,      // MCS 3
    00113     [ 27] =  864,        [ 28] =  816,        [ 29] =  735,      // MCS 4
    00114     [ 33] = 1152,        [ 34] = 1088,        [ 35] =  980,      // MCS 5
    00115     [ 39] = 1297,        [ 40] = 1225,        [ 41] = 1102,      // MCS 6
    00116     [ 45] = 1441,        [ 46] = 1361,        [ 47] = 1225,      // MCS 7
    00117     [ 51] = 1729,        [ 52] = 1633,        [ 53] = 1470,      // MCS 8
    00118     [ 57] = 1921,        [ 58] = 1814,        [ 59] = 1633,      // MCS 9
    00119     [ 63] = 2161,        [ 64] = 2041,        [ 65] = 1837,      // MCS 10
    00120     [ 69] = 2401,        [ 70] = 2268,        [ 71] = 2041,      // MCS 11
    00121 };
    00122
    00127 static const uint16_t TX_HE_26_TONE_TO_MIN_SEP[12*3] =
    00128 {
    00129     //GI0.8us            GI1.6us              GI3.2us            MCS Index
    00130     [  0] =  1,          [  1] =  1,          [  2] =  1,        // MCS 0
    00131     [  3] =  1,          [  4] =  1,          [  5] =  1,        // MCS 1
    00132     [  6] =  1,          [  7] =  1,          [  8] =  1,        // MCS 2
    00133     [  9] =  1,          [ 10] =  1,          [ 11] =  1,        // MCS 3
    00134     [ 12] =  1,          [ 13] =  1,          [ 14] =  1,        // MCS 4
    00135     [ 15] =  1,          [ 16] =  1,          [ 17] =  1,        // MCS 5
    00136     [ 18] =  1,          [ 19] =  1,          [ 20] =  1,        // MCS 6
    00137     [ 21] =  2,          [ 22] =  2,          [ 23] =  1,        // MCS 7
    00138     [ 24] =  2,          [ 25] =  2,          [ 26] =  2,        // MCS 8
    00139     [ 27] =  2,          [ 28] =  2,          [ 29] =  2,        // MCS 9
    00140     [ 30] =  2,          [ 31] =  2,          [ 32] =  2,        // MCS 10
    00141     [ 33] =  2,          [ 34] =  2,          [ 35] =  2,        // MCS 11
    00142 };
    00143
    00148 static const uint16_t TX_HE_52_TONE_TO_MIN_SEP[12*3] =
    00149 {
    00150     //GI0.8us            GI1.6us              GI3.2us            MCS Index
    00151     [  0] =  1,          [  1] =  1,          [  2] =  1,        // MCS 0
    00152     [  3] =  1,          [  4] =  1,          [  5] =  1,        // MCS 1
    00153     [  6] =  1,          [  7] =  1,          [  8] =  1,        // MCS 2
    00154     [  9] =  1,          [ 10] =  1,          [ 11] =  1,        // MCS 3
    00155     [ 12] =  2,          [ 13] =  2,          [ 14] =  2,        // MCS 4
    00156     [ 15] =  2,          [ 16] =  2,          [ 17] =  2,        // MCS 5
    00157     [ 18] =  2,          [ 19] =  2,          [ 20] =  2,        // MCS 6
    00158     [ 21] =  3,          [ 22] =  3,          [ 23] =  2,        // MCS 7
    00159     [ 24] =  3,          [ 25] =  3,          [ 26] =  3,        // MCS 8
    00160     [ 27] =  3,          [ 28] =  3,          [ 29] =  3,        // MCS 9
    00161     [ 30] =  4,          [ 31] =  4,          [ 32] =  3,        // MCS 10
    00162     [ 33] =  4,          [ 34] =  4,          [ 35] =  4,        // MCS 11
    00163 };
    00164
    00169 static const uint16_t TX_HE_106_TONE_TO_MIN_SEP[12*3] =
    00170 {
    00171     //GI0.8us            GI1.6us              GI3.2us            MCS Index
    00172     [  0] =  1,          [  1] =  1,          [  2] =  1,        // MCS 0
    00173     [  3] =  1,          [  4] =  1,          [  5] =  1,        // MCS 1
    00174     [  6] =  2,          [  7] =  2,          [  8] =  2,        // MCS 2
    00175     [  9] =  2,          [ 10] =  2,          [ 11] =  2,        // MCS 3
    00176     [ 12] =  3,          [ 13] =  3,          [ 14] =  3,        // MCS 4
    00177     [ 15] =  4,          [ 16] =  4,          [ 17] =  4,        // MCS 5
    00178     [ 18] =  5,          [ 19] =  4,          [ 20] =  4,        // MCS 6
    00179     [ 21] =  5,          [ 22] =  5,          [ 23] =  4,        // MCS 7
    00180     [ 24] =  6,          [ 25] =  6,          [ 26] =  5,        // MCS 8
    00181     [ 27] =  7,          [ 28] =  6,          [ 29] =  6,        // MCS 9
    00182     [ 30] =  8,          [ 31] =  7,          [ 32] =  6,        // MCS 10
    00183     [ 33] =  8,          [ 34] =  8,          [ 35] =  7,        // MCS 11
    00184 };
    00185
    00188 static const uint8_t fragb2b1_to_bitmap_len[4] =
    00189 {
    00190     [0] = 8,
    00191     [1] = 16,
    00192     [2] = 32,
    00193     [3] = 4
    00194 };
    00195
    00197 enum
    00198 {
    00199     RU_26TONE = 0,
    00200     RU_52TONE,
    00201     RU_106TONE,
    00202     RU_242TONE,
    00203     RU_484TONE,
    00204     RU_996TONE,
    00205     RU_2x996TONE,
    00206 };
    00207
    00208 static const uint16_t *ru_1us_tables[3] =
    00209 {
    00210     [RU_26TONE] = TX_HE_26_TONE_TO_MIN_SEP,
    00211     [RU_52TONE] = TX_HE_52_TONE_TO_MIN_SEP,
    00212     [RU_106TONE] = TX_HE_106_TONE_TO_MIN_SEP,
    00213 };
    00214
    00216 #define TX_HE_TB_PROG_MIN_TIME  10
    00217
    00219 #define TX_HE_TB_TIMEOUT   7000
    00220
    00222 #define TX_HE_TRIG_PERIOD  5000
    00223
    00225 #define TX_MU_EDCA_TIMER_PERIOD    (8 * 1024)
    00226
    00228 #define TX_HE_TB_MIN_PSDU_LEN CO_ALIGN4_HI(DELIMITER_LEN + MAC_QOS_NULL_FRAME_SIZE +     \
    00229                                            MAC_HTC_LEN + MAC_FCS_LEN)
    00230
    00232 #define BSR_SF_MAX  32768
    00233
    00235 #define BSR_QSIZE_MAX  254
    00236
    00238 #define BSR_BUFFERED_MAX (BSR_QSIZE_MAX * BSR_SF_MAX)
    00239
    00241 #define HTC_HE_UPH_DEF (MAC_HTC_HE_CTRL_ID_UPH | (0x07 << MAC_HTC_HE_CTRL_INFO_OFT))
    00242
    00243 /*
    00244  * TYPE and STRUCT DEFINITIONS
    00245  ****************************************************************************************
    00246  */
    00248 struct tx_he_tb_bsrp_qos_null_desc
    00249 {
    00251     struct tx_hd thd;
    00253     struct tx_pbd pbd;
    00255     uint16_t qos_ctrl;
    00256 };
    00257
    00259 struct tx_he_tb_bsrp_desc
    00260 {
    00262     struct tx_hd a_thd;
    00264     struct mac_hdr hdr;
    00266     struct tx_he_tb_bsrp_qos_null_desc qos_null[TID_MAX];
    00267 };
    00268
    00270 struct tx_he_tb_qos_null_desc
    00271 {
    00273     struct tx_hd thd;
    00275     struct mac_hdr_qos_htc payl;
    00276 };
    00277
    00280 struct tx_he_tb_ndp_desc
    00281 {
    00283     struct tx_hd thd;
    00284 };
    00285
    00287 struct tx_he_tb_desc
    00288 {
    00290     struct tx_he_tb_bsrp_desc brsp;
    00292     struct tx_he_tb_qos_null_desc qos_null;
    00294     struct tx_he_tb_ndp_desc ndp;
    00296     struct tx_policy_tbl tb_pol;
    00297 };
    00298
    00299 /*
    00300  * GLOBAL VARIABLE DEFINITION
    00301  ****************************************************************************************
    00302  */
    00303 struct txl_he_env_tag txl_he_env;
    00304
    00306 static struct tx_he_tb_desc he_tb_desc __SHAREDRAM;
    00307
    00308 /*
    00309  * FUNCTION BODIES
    00310  ****************************************************************************************
    00311  */
    00342 __INLINE uint8_t txl_he_bsr_get_sf_and_qsize(uint32_t buffered_all, uint32_t buffered_high,
    00343                                              uint8_t *qsize_all, uint8_t *qsize_high)
    00344 {
    00345     uint8_t sf;
    00346
    00347     if (buffered_all <= 4048)
    00348     {
    00349         sf = 0;
    00350         *qsize_all = (CO_ALIGNx_HI(buffered_all, 16)) / 16;
    00351         *qsize_high = (CO_ALIGNx_HI(buffered_high, 16)) / 16;
    00352     }
    00353     else if (buffered_all <= 64768)
    00354     {
    00355         sf = 1;
    00356         *qsize_all = (CO_ALIGNx_HI(buffered_all, 256)) / 256;
    00357         *qsize_high = (CO_ALIGNx_HI(buffered_high, 256)) / 256;
    00358     }
    00359     else if (buffered_all <= 518144)
    00360     {
    00361         sf = 2;
    00362         *qsize_all = (CO_ALIGNx_HI(buffered_all, 2048)) / 2048;
    00363         *qsize_high = (CO_ALIGNx_HI(buffered_high, 2048)) / 2048;
    00364     }
    00365     else
    00366     {
    00367         buffered_all = (buffered_all > BSR_BUFFERED_MAX) ? BSR_BUFFERED_MAX : buffered_all;
    00368         buffered_high = (buffered_high > BSR_BUFFERED_MAX) ? BSR_BUFFERED_MAX : buffered_high;
    00369         sf = 3;
    00370         *qsize_all = (CO_ALIGNx_HI(buffered_all, 32768)) / 32768;
    00371         *qsize_high = (CO_ALIGNx_HI(buffered_high, 32768)) / 32768;
    00372     }
    00373
    00374     return sf;
    00375 }
    00376
    00387 static uint32_t txl_he_dur_to_len(uint32_t rc)
    00388 {
    00389     uint32_t mcs_idx = (rc & MCS_INDEX_TX_RCX_MASK) >> MCS_INDEX_TX_RCX_OFT;
    00390     uint32_t gi = (rc & HE_GI_TYPE_TX_RCX_MASK) >> HE_GI_TYPE_TX_RCX_OFT;
    00391     uint32_t bw = (rc & BW_TX_RCX_MASK) >> BW_TX_RCX_OFT;
    00392     int idx = mcs_idx * 6 + 3 * (bw >> 1) + gi;
    00393     int shift = bw & 0x01;
    00394     return (((uint32_t)TX_HE_RATE_TO_32US_LEN[idx]) << shift);
    00395 }
    00396
    00407 static void txl_he_txop_dur_rtscts_thres_apply(uint32_t *rc, uint32_t frm_len,
    00408                                                uint16_t txop_dur_rts_thres)
    00409 {
    00410     uint32_t rc_loc = *rc;
    00411
    00412     if (txl_he_is_he_su(rc_loc))
    00413     {
    00414         // As the TXOP duration RTS/CTS threshold cannot be 0, let's decrease it by one in
    00415         // order to take into account an approximate value of the preamble duration
    00416         uint32_t thres = txl_he_dur_to_len(rc_loc) * (txop_dur_rts_thres - 1);
    00417
    00418         if (frm_len > thres)
    00419         {
    00420             // Check if a protection is already activated. If yes we keep the same rate
    00421             // as it might be an ERP protection sent in DSSS.
    00422             if ((rc_loc & PROT_FRM_EX_RCX_MASK) != PROT_NO_PROT)
    00423             {
    00424                 // Just clear the type of protection to replace it by RTS/CTS
    00425                 rc_loc &= ~PROT_FRM_EX_RCX_MASK;
    00426                 rc_loc |= PROT_RTS_CTS;
    00427             }
    00428             else
    00429             {
    00430                 uint8_t bw, rate, mcs;
    00431
    00432                 // Retrieve BW and MCS of the PPDU in order to compute the protection parameters
    00433                 bw = (rc_loc & BW_TX_RCX_MASK) >> BW_TX_RCX_OFT;
    00434                 mcs = rc_loc & VHT_MCS_MASK;
    00435                 rate = mcs > 2 ? HW_RATE_24MBPS : HW_RATE_6MBPS;
    00436                 rc_loc &= ~(PROT_FRM_EX_RCX_MASK | MCS_INDEX_PROT_TX_RCX_MASK | BW_PROT_TX_RCX_MASK |
    00437                                                                        FORMAT_MOD_PROT_TX_RCX_MASK);
    00438                 rc_loc |= (bw << BW_PROT_TX_RCX_OFT) | (rate << MCS_INDEX_PROT_TX_RCX_OFT) | PROT_RTS_CTS;
    00439                 rc_loc |= FORMATMOD_NON_HT_DUP_OFDM << FORMAT_MOD_PROT_TX_RCX_OFT;
    00440             }
    00441
    00442             *rc = rc_loc;
    00443         }
    00444     }
    00445 }
    00446
    00459 static bool txl_he_edca_queue_halted(uint8_t ac)
    00460 {
    00461     // Set the header pointer and the new head bit according to the access category
    00462     switch (ac)
    00463     {
    00464         #if NX_BEACONING
    00465         case AC_BCN:
    00466             return(nxmac_tx_bcn_state_getf() == 0);
    00467         #endif
    00468         case AC_VO:
    00469             return(nxmac_tx_ac_3_state_getf() == 0);
    00470         case AC_VI:
    00471             return(nxmac_tx_ac_2_state_getf() == 0);
    00472         case AC_BE:
    00473             return(nxmac_tx_ac_1_state_getf() == 0);
    00474         case AC_BK:
    00475             return(nxmac_tx_ac_0_state_getf() == 0);
    00476         default:
    00477             ASSERT_ERR(0);
    00478             break;
    00479     }
    00480     return false;
    00481 }
    00482
    00493 static void txl_he_restart_edca(uint8_t ac)
    00494 {
    00495     struct mu_edca_param_tag *mu_edca_param = &txl_he_env.mu_edca.params[ac];
    00496
    00497     if (!mu_edca_param->edca_off)
    00498         return;
    00499
    00500     mu_edca_param->edca_off = false;
    00501
    00502     if (mu_edca_param->first_frame_exch)
    00503         txl_cntrl_newhead(CPU2HW(mu_edca_param->first_frame_exch), ac);
    00504
    00505     mu_edca_param->first_frame_exch = NULL;
    00506 }
    00507
    00518 static void txl_he_mu_edca_timer(void *env)
    00519 {
    00520     struct mu_edca_tag *mu_edca = &txl_he_env.mu_edca;
    00521     uint32_t *edca_reg = HW2CPU(NXMAC_EDCA_AC_0_ADDR);
    00522     uint8_t mu_edca_active = 0;
    00523
    00524     // Perform all this handling with interrupt disabled to avoid corruption from HE TB
    00525     // TX interrupt
    00526     GLOBAL_INT_DISABLE();
    00527
    00528     // Go through the different access categories
    00529     for (int i = 0; i < AC_MAX; i++)
    00530     {
    00531         uint8_t ac_bit = CO_BIT(i);
    00532
    00533         // Check if the EDCA queue is now stopped
    00534         if (mu_edca->edca_stopping & ac_bit)
    00535         {
    00536             if (!txl_he_edca_queue_halted(i))
    00537             {
    00538                 // Mark MU EDCA as active for this queue
    00539                 mu_edca_active |= ac_bit;
    00540                 continue;
    00541             }
    00542
    00543             mu_edca->edca_stopping &= ~ac_bit;
    00544         }
    00545
    00546         // Check if we had HE TB activity on this AC during the previous period
    00547         if (mu_edca->he_tb_activity & ac_bit)
    00548         {
    00549             uint8_t aifsn = mu_edca->params[i].edca & 0x0F;
    00550             mu_edca->he_tb_activity &= ~ac_bit;
    00551             if (aifsn)
    00552             {
    00553                 // Apply the latest MU EDCA value received for this AC
    00554                 edca_reg[i] = mu_edca->params[i].edca;
    00555
    00556                 // Restart EDCA if required
    00557                 txl_he_restart_edca(i);
    00558             }
    00559             else if (!mu_edca->params[i].edca_off)
    00560             {
    00561                 // AIFSN=0, disable EDCA
    00562                 mu_edca->params[i].edca_off = true;
    00563                 mu_edca->edca_stopping |= ac_bit;
    00564             }
    00565
    00566             // Reset the timer to its default
    00567             mu_edca->params[i].timer = mu_edca->params[i].timeout;
    00568             // Mark MU EDCA as active for this queue
    00569             mu_edca_active |= ac_bit;
    00570         }
    00571         // Check if have the MU EDCA timer is pending for this AC
    00572         else if (mu_edca->params[i].timer > 0)
    00573         {
    00574             // Decrement the timer
    00575             mu_edca->params[i].timer--;
    00576
    00577             if (mu_edca->params[i].timer == 0)
    00578             {
    00579                 // Put back the normal EDCA values
    00580                 edca_reg[i] = txl_he_env.tb_vif->txq_params[i];
    00581
    00582                 // Restart EDCA if required
    00583                 txl_he_restart_edca(i);
    00584             }
    00585             else
    00586             {
    00587                 // Mark MU EDCA as active for this queue
    00588                 mu_edca_active |= ac_bit;
    00589             }
    00590         }
    00591     }
    00592
    00593     // If MU EDCA is still active, restart the timer
    00594     if (mu_edca_active)
    00595         mm_timer_set(&mu_edca->timer, hal_machw_time() + TX_MU_EDCA_TIMER_PERIOD);
    00596     else
    00597         mu_edca->timer.cb = NULL;
    00598
    00599     // Restore interrupts
    00600     GLOBAL_INT_RESTORE();
    00601 }
    00602
    00612 static void txl_he_mu_edca_start(uint8_t ac)
    00613 {
    00614     struct mu_edca_tag *mu_edca = &txl_he_env.mu_edca;
    00615
    00616     // Check if we have valid MU EDCA parameters available
    00617     if (!mu_edca->valid)
    00618         return;
    00619
    00620     // Indicate HE TB activity on this access category
    00621     mu_edca->he_tb_activity |= CO_BIT(ac);
    00622
    00623     // Start the MU EDCA timer if not already done
    00624     if (!txl_he_env.mu_edca.timer.cb)
    00625     {
    00626         ASSERT_REC(txl_he_edca_queue_halted(ac));
    00627         mu_edca->timer.cb = txl_he_mu_edca_timer;
    00628         txl_he_mu_edca_timer(mu_edca);
    00629     }
    00630
    00631 }
    00632
    00641 static void txl_he_mu_edca_stop(void)
    00642 {
    00643     struct mu_edca_tag *mu_edca = &txl_he_env.mu_edca;
    00644     uint32_t *edca_reg = HW2CPU(NXMAC_EDCA_AC_0_ADDR);
    00645
    00646     // Go through the different access categories
    00647     for (int i = 0; i < AC_MAX; i++)
    00648     {
    00649         // Put back the normal EDCA values
    00650         edca_reg[i] = txl_he_env.tb_vif->txq_params[i];
    00651
    00652         // Restart EDCA if required
    00653         txl_he_restart_edca(i);
    00654     }
    00655
    00656     // Disable the MU EDCA timer
    00657     mm_timer_clear(&mu_edca->timer);
    00658     mu_edca->timer.cb = NULL;
    00659 }
    00660
    00661 #if NX_UMAC_PRESENT && NX_BEACONING
    00662
    00673 static void txl_he_trig_time(void *env)
    00674 {
    00675     struct sta_info_tag *sta = (struct sta_info_tag *)env;
    00676
    00677     if (sta->valid)
    00678     {
    00679         mm_timer_set(&txl_he_env.trig_timer, hal_machw_time() + TX_HE_TRIG_PERIOD);
    00680         txl_frame_send_he_trigger(sta->staid, HE_TRIG_TYPE_BASIC, 2500, 37, 5, AC_VI,
    00681                                   NULL, NULL);
    00682     }
    00683     else
    00684     {
    00685         txl_he_env.trig_timer.cb = NULL;
    00686         txl_he_env.trig_timer.env = NULL;
    00687     }
    00688 }
    00689 #endif // NX_UMAC_PRESENT && NX_BEACONING
    00690
    00696 static void txl_he_tb_halt_queue(void)
    00697 {
    00698     nxmac_dma_cntrl_set(NXMAC_HALT_TB_AFTER_TXOP_BIT);
    00699     while(nxmac_tx_tb_state_getf() != 0);
    00700     nxmac_dma_cntrl_clear(NXMAC_HALT_TB_AFTER_TXOP_BIT);
    00701 }
    00702
    00709 __INLINE void txl_he_tb_timer_start(void)
    00710 {
    00711     nxmac_abs_timer_set(HAL_HE_TB_TIMER, hal_machw_time() + TX_HE_TB_TIMEOUT);
    00712     nxmac_timers_int_event_clear(HAL_HE_TB_TIMER_BIT);
    00713     nxmac_timers_int_un_mask_set(nxmac_timers_int_un_mask_get() | HAL_HE_TB_TIMER_BIT);
    00714
    00715     txl_he_env.tb_ongoing = true;
    00716 }
    00717
    00724 __INLINE void txl_he_tb_timer_clear(void)
    00725 {
    00726     uint32_t timer_msk = nxmac_timers_int_un_mask_get();
    00727
    00728     nxmac_timers_int_un_mask_set(timer_msk & ~HAL_HE_TB_TIMER_BIT);
    00729     nxmac_timers_int_event_clear(HAL_HE_TB_TIMER_BIT);
    00730
    00731     txl_he_env.tb_ongoing = false;
    00732 }
    00733
    00745 static uint32_t txl_he_tb_psdulen_get(void)
    00746 {
    00747     uint32_t common;
    00748     uint32_t user;
    00749     uint32_t l_length;
    00750     uint32_t gi_ltf_type;
    00751     uint32_t mcs;
    00752     uint32_t rulen;
    00753     uint32_t psdulen;
    00754     struct he_trigger_tag *he_tb = &txl_he_env.trigger;
    00755
    00756     // Get HE TB parameters from the trigger frame
    00757     common = nxmac_rx_he_trig_common_info_get();
    00758     user = nxmac_rx_he_trig_user_info_get();
    00759     l_length = (common & NXMAC_UL_LENGTH_MASK) >> NXMAC_UL_LENGTH_LSB;
    00760     gi_ltf_type = (common & NXMAC_UL_GILTF_TYPE_MASK) >> NXMAC_UL_GILTF_TYPE_LSB;
    00761     mcs = (user & NXMAC_UL_MCS_MASK) >> NXMAC_UL_MCS_LSB;
    00762     rulen = (user & NXMAC_UL_RU_SIZE_MASK) >> NXMAC_UL_RU_SIZE_LSB;
    00763     he_tb->trig_type = (common & NXMAC_UL_TRIGGER_TYPE_MASK) >> NXMAC_UL_TRIGGER_TYPE_LSB;
    00764     he_tb->ul_bw = (common & NXMAC_UL_BW_MASK) >> NXMAC_UL_BW_LSB;
    00765     he_tb->ul_length = l_length;
    00766     he_tb->gi_type = gi_ltf_type < 2 ? 1 : 2;
    00767     he_tb->uora = (user & NXMAC_UL_RU_TYPE_BIT) != 0 ? true : false;
    00768     he_tb->ul_mcs = mcs;
    00769     he_tb->ul_nss = (user & NXMAC_UL_NSS_MASK) >> NXMAC_UL_NSS_LSB;
    00770     he_tb->ru_size = rulen;
    00771     if (he_tb->trig_type == HE_TRIG_TYPE_BASIC)
    00772     {
    00773         uint32_t td_user = (user & NXMAC_TD_USER_INFO_SUBFIELD_MASK)
    00774                                                        >> NXMAC_TD_USER_INFO_SUBFIELD_LSB;
    00775         he_tb->pref_ac = mac_aci2ac[(td_user & HE_TRIG_PREF_AC_MSK) >> HE_TRIG_PREF_AC_OFT];
    00776         he_tb->spacing_factor = (td_user & HE_TRIG_SPC_FACTOR_MSK) >> HE_TRIG_SPC_FACTOR_OFT;
    00777     }
    00778
    00779     while (!nxmac_ul_psdu_len_valid_getf());
    00780     psdulen = nxmac_ul_psdu_len_getf();
    00781
    00782     return CO_ALIGN4_LO(psdulen);
    00783 }
    00784
    00791 static void txl_he_tb_params_compute(void)
    00792 {
    00793     struct he_trigger_tag *he_tb = &txl_he_env.trigger;
    00794     uint16_t len_1us;
    00795     uint32_t max_len_phy;
    00796     struct sta_info_tag *sta = he_tb->sta;
    00797
    00798     // Compute the maximum length we can put inside the HE TB
    00799     max_len_phy = txl_he_tb_psdulen_get();
    00800
    00801     // Now use the correct table to retrieve the parameters
    00802     switch (he_tb->ru_size)
    00803     {
    00804         case RU_26TONE:
    00805         case RU_52TONE:
    00806         case RU_106TONE:
    00807             len_1us =  ru_1us_tables[he_tb->ru_size][he_tb->ul_mcs * 3 + he_tb->gi_type];
    00808             break;
    00809         default:
    00810             len_1us = txl_he_idx_to_1us_len_get(he_tb->ul_mcs * 6 + he_tb->gi_type,
    00811                                                 he_tb->ru_size - 3);
    00812             break;
    00813     }
    00814
    00815     he_tb->max_len = co_min(max_len_phy, sta->ampdu_size_max_he);
    00816     he_tb->mmss = len_1us * (uint16_t)sta->ampdu_spacing_min *
    00817                   (uint16_t)(1 << he_tb->spacing_factor);
    00818     // Get UPH from HW register and format the +HTC HE Variant field
    00819     he_tb->uph = MAC_HTC_HE(MAC_HTC_HE_CTRL(UPH, nxmac_he_tbuph_control_getf()));
    00820 }
    00821
    00837 static int txl_he_m_ba_aid_tid_len(struct ba_msta_aid_tid_info *aid_tid_info,
    00838                                    int remaining_len)
    00839 {
    00840     int len;
    00841     uint16_t frag;
    00842     uint16_t aid = (aid_tid_info->aid_tid & BA_MULTI_STA_AID_MSK) >> BA_MULTI_STA_AID_OFT;
    00843
    00844     if (aid == 2045)
    00845     {
    00846         return 12;
    00847     }
    00848     else if (aid_tid_info->aid_tid & BA_MULTI_STA_ACK_BIT)
    00849     {
    00850         return 2;
    00851     }
    00852     else if (remaining_len < (int)sizeof_b(*aid_tid_info))
    00853     {
    00854         return -1;
    00855     }
    00856
    00857     // Get fragment number inside SSC
    00858     frag = aid_tid_info->ssc_bitmap.ssc & MAC_SEQCTRL_FRAG_MSK;
    00859
    00860     if (frag & CO_BIT(3))
    00861         return -1;
    00862
    00863     len = fragb2b1_to_bitmap_len[frag >> 1] + sizeof_b(*aid_tid_info);
    00864
    00865     if (remaining_len < len)
    00866         return -1;
    00867
    00868     // All checks passed, return length
    00869     return len;
    00870 }
    00871
    00877 static void txl_he_tb_set_rc_info(void)
    00878 {
    00879     #if NX_UMAC_PRESENT
    00880     struct he_trigger_tag *he_tb = &txl_he_env.trigger;
    00881     struct rc_sta_stats *rc_ss = he_tb->sta->pol_tbl.sta_stats;
    00882     struct rc_rate_stats *rc_rs = &rc_ss->rate_stats[RC_MAX_N_SAMPLE];
    00883
    00884     rc_rs->rate_config = (FORMATMOD_HE_MU << FORMAT_MOD_TX_RCX_OFT) |
    00885              (he_tb->ul_mcs << VHT_MCS_OFT) | (he_tb->gi_type << HE_GI_TYPE_TX_RCX_OFT) |
    00886              (he_tb->ul_bw << BW_TX_RCX_OFT) |(he_tb->ul_nss << VHT_NSS_OFT);
    00887     rc_rs->ru_and_length = he_tb->ru_size | (he_tb->ul_length << 3);
    00888     #endif
    00889 }
    00890
    00898 static void txl_he_tb_ppdu_chain(struct tx_hd *thd)
    00899 {
    00900     thd->statinfo &= NUM_MPDU_RETRIES_MSK;
    00901     thd->nextfrmexseq_ptr = 0;
    00902     thd->policyentryaddr = CPU2HW(&he_tb_desc.tb_pol);
    00903     nxmac_tx_tb_head_ptr_set(CPU2HW(thd));
    00904     nxmac_dma_cntrl_set(NXMAC_TX_TB_NEW_HEAD_BIT);
    00905
    00906     txl_he_env.trigger.trig_valid = false;
    00907 }
    00908
    00918 static void txl_he_tb_send_ndp(void)
    00919 {
    00920     struct tx_hd *thd = &he_tb_desc.ndp.thd;
    00921
    00922     txl_he_tb_ppdu_chain(thd);
    00923 }
    00924
    00933 static void txl_he_tb_send_qos_null(void)
    00934 {
    00935     struct he_trigger_tag *he_tb = &txl_he_env.trigger;
    00936     struct tx_hd *thd = &he_tb_desc.qos_null.thd;
    00937     struct mac_hdr_qos_htc *payl = &he_tb_desc.qos_null.payl;
    00938
    00939     payl->addr1 = he_tb->ta;
    00940     payl->addr2 = txl_he_env.tb_vif->mac_addr;
    00941     payl->addr3 = he_tb->ta;
    00942     payl->htc = he_tb->uph;
    00943
    00944     txl_he_tb_ppdu_chain(thd);
    00945 }
    00946
    00954 __INLINE void txl_he_tb_send_bsrp(struct he_trigger_tag *he_tb)
    00955 {
    00956     struct tx_hd *a_thd = &he_tb_desc.brsp.a_thd;
    00957     struct tx_hd *thd_prev = a_thd;
    00958     struct mac_hdr *hdr = &he_tb_desc.brsp.hdr;
    00959     uint8_t tid, queue_size;
    00960     uint16_t nb_delims, subfrm_len;
    00961     uint32_t buffered;
    00962     uint32_t whichdesc = WHICHDESC_AMPDU_FIRST;
    00963
    00964     a_thd->frmlen = 0;
    00965
    00966     hdr->addr1 = he_tb->sta->mac_addr;
    00967     hdr->addr2 = txl_he_env.tb_vif->mac_addr;
    00968     hdr->addr3 = he_tb->sta->mac_addr;
    00969
    00970     // Compute the new number of delimiters and the sub-frame length
    00971     nb_delims = txl_agg_mpdu_nb_delims(&he_tb_desc.brsp.qos_null[0].thd, he_tb->mmss);
    00972     subfrm_len = txl_mpdu_subframe_len(&he_tb_desc.brsp.qos_null[0].thd) + nb_delims * DELIMITER_LEN;
    00973
    00974     for (tid = 0; tid < TID_MAX; tid++)
    00975     {
    00976         struct tx_hd *thd = &he_tb_desc.brsp.qos_null[tid].thd;
    00977         uint16_t *qos = &he_tb_desc.brsp.qos_null[tid].qos_ctrl;
    00978
    00979         buffered = macif_buffered_get(he_tb->sta->staid, tid);
    00980         if (!buffered)
    00981             continue;
    00982
    00983         // Check if the MPDU fits into the remaining length
    00984         if ((a_thd->frmlen + subfrm_len) > he_tb->max_len)
    00985             break;
    00986
    00987         queue_size = txl_he_get_queue_size(buffered);
    00988         // set the 4th bit of the QoS Control field
    00989         *qos = MAC_QOSCTRL_QUEUE_SIZE_PRESENT | MAC_QOSCTRL_ACK_NOACK;
    00990         // Add the queue_size
    00991         *qos |= queue_size << MAC_QOSCTRL_AMSDU_OFT;
    00992         // Add the TID
    00993         *qos |= tid << MAC_QOSCTRL_UP_OFT;
    00994
    00995         thd->policyentryaddr = 0;
    00996         thd->statinfo = 0;
    00997         thd->macctrlinfo2 = whichdesc | (nb_delims << NB_BLANK_DELIM_OFT);
    00998         whichdesc = WHICHDESC_AMPDU_INT;
    00999         thd_prev->nextmpdudesc_ptr = CPU2HW(thd);
    01000
    01001         a_thd->frmlen += subfrm_len;
    01002
    01003         thd_prev = thd;
    01004     }
    01005
    01006     if (a_thd->frmlen)
    01007     {
    01008         thd_prev->nextmpdudesc_ptr = 0;
    01009         if ((thd_prev->macctrlinfo2 & WHICHDESC_MSK) == WHICHDESC_AMPDU_FIRST)
    01010         {
    01011             // Send QoS NULL as singleton
    01012             thd_prev->macctrlinfo2 = WHICHDESC_UNFRAGMENTED_MSDU;
    01013             txl_he_tb_ppdu_chain(thd_prev);
    01014         }
    01015         else
    01016         {
    01017             thd_prev->macctrlinfo2 &= ~WHICHDESC_MSK;
    01018             thd_prev->macctrlinfo2 |= WHICHDESC_AMPDU_LAST;
    01019             txl_he_tb_ppdu_chain(a_thd);
    01020         }
    01021     }
    01022     else
    01023     {
    01024         struct tx_hd *thd = &he_tb_desc.brsp.qos_null[0].thd;
    01025         uint16_t *qos = &he_tb_desc.brsp.qos_null[0].qos_ctrl;
    01026
    01027         // No traffic present on any TID, simply send a QoS-NULL with TID0 and queue size
    01028         // equal to 0
    01029         *qos = MAC_QOSCTRL_QUEUE_SIZE_PRESENT | MAC_QOSCTRL_ACK_NOACK;
    01030         thd->macctrlinfo2 = WHICHDESC_UNFRAGMENTED_MSDU;
    01031         thd->nextmpdudesc_ptr = 0;
    01032
    01033         txl_he_tb_ppdu_chain(thd);
    01034     }
    01035 }
    01043 static void txl_he_tb_send_data(struct tx_hd *thd)
    01044 {
    01045     #if NX_PROFILING_ON
    01046     struct he_trigger_tag *he_tb = &txl_he_env.trigger;
    01047     #endif
    01048
    01049     PROF_TX_AC_IRQ_SET(he_tb->ac);
    01050
    01051     // Start the TX activity timer
    01052     txl_he_tb_timer_start();
    01053
    01054     txl_he_tb_ppdu_chain(thd);
    01055 }
    01056
    01066 static void txl_he_tb_free_done(struct txdesc *txdesc, uint8_t access_category)
    01067 {
    01068     struct txl_list *txlist = &txl_cntrl_env.txlist[access_category];
    01069     struct tx_hd *txhd = &txdesc->lmac.hw_desc->thd;
    01070
    01071     // Pop picked txdesc definitively from list
    01072     co_list_pop_front(&(txlist->transmitting[0]));
    01073
    01074     // We have one PPDU less in the TX path
    01075     txlist->ppdu_cnt--;
    01076
    01077     #if NX_TX_FRAME
    01078     // Check if the frame was generated internally
    01079     if (is_int_frame(txdesc))
    01080     {
    01081         // Put the descriptor in the CFM queue
    01082         txl_frame_cfm(txdesc);
    01083     }
    01084     else
    01085     #endif
    01086     {
    01087         // Put the descriptor in the CFM queue
    01088         txl_cfm_push(txdesc, txhd->statinfo, access_category);
    01089     }
    01090 }
    01091
    01105 static struct tx_hd *txl_he_tb_ppdu_get(struct txdesc **txdesc_next)
    01106 {
    01107     struct txdesc *txdesc = NULL;
    01108     int access_category;
    01109     struct he_trigger_tag *he_tb = &txl_he_env.trigger;
    01110
    01111     *txdesc_next = NULL;
    01112
    01113     // Check we have already an HE TB ongoing
    01114     if (txl_he_env.tb_ongoing)
    01115         return NULL;
    01116
    01117     // For now only consider the AC specified in the trigger frame
    01118     for (access_category = AC_VO; access_category >= he_tb->pref_ac; access_category--)
    01119     {
    01120         struct txl_list *txlist = &txl_cntrl_env.txlist[access_category];
    01121
    01122         he_tb->ac = access_category;
    01123
    01124         // In case we were waiting for the BAR THD to be updated, it means that we did not
    01125         // receive the BlockAck of the last A-MPDU transmission. Don't program any data
    01126         // in the HE TB in that case
    01127         if (txlist->chk_state == BAR_THD_CHK_STATE)
    01128             return NULL;
    01129
    01130         while (1)
    01131         {
    01132             struct tx_hd *thd;
    01133             struct tx_agg_desc *agg_desc;
    01134
    01135             // Pick first txdesc in transmitting list
    01136             txdesc = (struct txdesc *)co_list_pick(&(txlist->transmitting[0]));
    01137
    01138             // Check if a descriptor is waiting to be confirmed
    01139             if (txdesc == NULL)
    01140                 break;
    01141
    01142             // Check the doneTx status bit
    01143             if (!is_mpdu_agg(txdesc) && (txdesc->lmac.hw_desc->thd.statinfo & DESC_DONE_TX_BIT))
    01144             {
    01145                 txl_he_tb_free_done(txdesc, access_category);
    01146                 continue;
    01147             }
    01148
    01149             thd = txl_agg_he_tb_prep(txdesc, txdesc_next, he_tb->max_len, he_tb->mmss,
    01150                                      he_tb->ac);
    01151
    01152             if (!thd)
    01153                 break;
    01154
    01155             agg_desc = txdesc->lmac.agg_desc;
    01156
    01157             // All the HE TB PPDU transmissions are done with a AGG descriptor attached
    01158             ASSERT_ERR(agg_desc != NULL);
    01159
    01160             // Indicate that this AGG descriptor corresponds to a HE TB PPDU transmission
    01161             // This will be used when deciding whether the +HTC value to put is the BSR
    01162             // or the UPH
    01163             agg_desc->status |= AGG_TB;
    01164             return thd;
    01165         }
    01166     }
    01167
    01168     return NULL;
    01169 }
    01170
    01180 static void txl_he_tb_ac_reconfig(struct txdesc *txdesc)
    01181 {
    01182     struct he_trigger_tag *he_tb = &txl_he_env.trigger;
    01183     struct mu_edca_param_tag *mu_edca_param = &txl_he_env.mu_edca.params[he_tb->ac];
    01184     struct txl_list *txlist = &txl_cntrl_env.txlist[he_tb->ac];
    01185     struct tx_hd *last_thd = NULL;
    01186     struct tx_hd *next_thd = NULL;
    01187
    01188     // First halt the queue
    01189     txl_cntrl_halt_ac(he_tb->ac);
    01190
    01191     // Check if a previous A-MPDU descriptor was saved and needs to be freed
    01192     txl_agg_check_saved_agg_desc(he_tb->ac);
    01193
    01194     do
    01195     {
    01196         // Check if a packet could be available for transmission after the HE TB PPDU
    01197         // transmission
    01198         if (!txdesc)
    01199             break;
    01200
    01201         if (is_mpdu_agg(txdesc))
    01202         {
    01203             struct tx_agg_desc *agg_desc = txdesc->lmac.agg_desc;
    01204
    01205             // Check if the next packet to transmit is a remainder of a possibly split
    01206             // A-MPDU we programmed as HE TB, or the head of a fresh A-MPDU
    01207             if (is_mpdu_last(txdesc))
    01208             {
    01209                 // The programmed HE TB PPDU is a split A-MPDU, and only one MPDU
    01210                 // composes the remainder of this A-MPDU. Let's change it into a
    01211                 // singleton MPDU
    01212                 next_thd = last_thd = txl_agg_change_to_singleton(txdesc, false);
    01213
    01214                 if (next_thd)
    01215                     next_thd->nextfrmexseq_ptr = agg_desc->bar_thd.nextfrmexseq_ptr;
    01216
    01217                 txl_agg_desc_free(agg_desc);
    01218             }
    01219             else if (is_mpdu_interm(txdesc))
    01220             {
    01221                 // The programmed HE TB PPDU is a split A-MPDU, and several packets
    01222                 // compose the remainder of this A-MPDU. Let's set the present MPDU as
    01223                 // the first of the next A-MPDU to transmit
    01224                 next_thd = txl_agg_set_new_ampdu_head(txdesc, &last_thd);
    01225             }
    01226             // The next packet of the queue is the head of a fresh A-MPDU, let's verify
    01227             // if it is ready to be programmed or not
    01228             else if ((agg_desc->status & (AGG_FORMATTED | AGG_DOWNLOADED)) ==
    01229                                                         (AGG_FORMATTED | AGG_DOWNLOADED))
    01230             {
    01231                 next_thd = &agg_desc->a_thd;
    01232                 last_thd = &agg_desc->bar_thd;
    01233             }
    01234         }
    01235         else
    01236         {
    01237             if (txl_buffer_get(txdesc) == NULL)
    01238                 break;
    01239
    01240             next_thd = last_thd = &txdesc->lmac.hw_desc->thd;
    01241
    01242             // Remove the +HTC field if required
    01243             if (!is_htc_sglt_allowed(txdesc))
    01244                 txl_buffer_remove_htc(next_thd);
    01245         }
    01246
    01247         // Ensure that we really have something to program as next frame exchange
    01248         if (next_thd == NULL)
    01249             break;
    01250
    01251         // Remind the THD of the next frame exchange sequence to be chained
    01252         mu_edca_param->first_frame_exch = next_thd;
    01253         if (last_thd->nextfrmexseq_ptr == 0)
    01254             txlist->last_frame_exch = last_thd;
    01255
    01256         // All checks are OK, so we can return
    01257         return;
    01258     } while(0);
    01259
    01260     // Nothing ready to program as next frame exchange, clear all the queue parameters
    01261     txlist->last_frame_exch = NULL;
    01262     mu_edca_param->first_frame_exch = NULL;
    01263 }
    01264
    01271 static void txl_he_tb_ppdu_send(void)
    01272 {
    01273     struct txdesc *txdesc = NULL;
    01274     struct tx_hd *thd = NULL;
    01275     struct he_trigger_tag *he_tb = &txl_he_env.trigger;
    01276
    01277     // Check validity of trigger frame
    01278     if (!he_tb->trig_valid)
    01279     {
    01280         // If not valid, we simply send a NDP in response, in order to avoid getting
    01281         // a PHY error
    01282         txl_he_tb_send_ndp();
    01283         return;
    01284     }
    01285
    01286     // BSRP Trigger frame
    01287     if (he_tb->trig_type == HE_TRIG_TYPE_BSRP)
    01288     {
    01289         txl_he_tb_send_bsrp(he_tb);
    01290         return;
    01291     }
    01292
    01293     // Get the information about the HE TB PPDU to transmit
    01294     thd = txl_he_tb_ppdu_get(&txdesc);
    01295
    01296     if (thd == NULL)
    01297     {
    01298         txl_he_tb_send_qos_null();
    01299         return;
    01300     }
    01301
    01302     // Program the HE TB PPDU for transmission
    01303     txl_he_tb_send_data(thd);
    01304
    01305     // Re-configure the HW AC queue with the next packet to transmit
    01306     txl_he_tb_ac_reconfig(txdesc);
    01307 }
    01308
    01314 static void txl_he_tb_desc_init(void)
    01315 {
    01316     struct tx_hd *thd;
    01317     struct mac_hdr_qos *payl;
    01318     struct mac_hdr *hdr;
    01319     struct tx_policy_tbl *pol = &he_tb_desc.tb_pol;
    01320     uint8_t tid;
    01321
    01322     // Reset all fields in a all descriptors
    01323     memset(&he_tb_desc, 0, sizeof(he_tb_desc));
    01324
    01325     /*
    01326      ************************************************************************************
    01327      * HE TB policy table
    01328      ************************************************************************************
    01329      */
    01330     pol->upatterntx = POLICY_TABLE_PATTERN;
    01331
    01332     /*
    01333      ************************************************************************************
    01334      * Default QoS-NULL descriptors
    01335      ************************************************************************************
    01336      */
    01337     payl = (struct mac_hdr_qos *)&he_tb_desc.qos_null.payl;
    01338     thd = &he_tb_desc.qos_null.thd;
    01339
    01340     // Fill payload
    01341     payl->fctl = MAC_FCTRL_QOS_NULL | MAC_FCTRL_TODS;
    01342     payl->qos = MAC_QOSCTRL_ACK_NOACK | MAC_QOSCTRL_HE_QUEUE_SIZE;
    01343
    01344     // Initialize THD descriptor
    01345     thd->upatterntx = TX_HEADER_DESC_PATTERN;
    01346     thd->policyentryaddr = CPU2HW(pol);
    01347     thd->frmlen = MAC_QOS_NULL_FRAME_SIZE + MAC_HTC_LEN + MAC_FCS_LEN;
    01348     thd->datastartptr = CPU2HW(payl);
    01349     thd->dataendptr = (uint32_t)thd->datastartptr + thd->frmlen - 1;
    01350     thd->first_pbd_ptr = 0;
    01351     thd->macctrlinfo1 = EXPECTED_ACK_NO_ACK;
    01352
    01353     /*
    01354      ************************************************************************************
    01355      * Default NDP descriptors
    01356      ************************************************************************************
    01357      */
    01358     thd = &he_tb_desc.ndp.thd;
    01359     thd->upatterntx = TX_HEADER_DESC_PATTERN;
    01360     thd->macctrlinfo1 = EXPECTED_ACK_NO_ACK;
    01361     thd->policyentryaddr = CPU2HW(pol);
    01362
    01363     /*
    01364      ************************************************************************************
    01365      * Default BSRP descriptors
    01366      ************************************************************************************
    01367      */
    01368     thd = &he_tb_desc.brsp.a_thd;
    01369     thd->upatterntx = TX_HEADER_DESC_PATTERN;
    01370     thd->macctrlinfo2 = WHICHDESC_AMPDU_EXTRA;
    01371     thd->policyentryaddr = CPU2HW(pol);
    01372     hdr = &he_tb_desc.brsp.hdr;
    01373     hdr->fctl = MAC_FCTRL_QOS_NULL | MAC_FCTRL_TODS;
    01374     for (tid = 0; tid < TID_MAX; tid++)
    01375     {
    01376         struct tx_pbd *pbd = &he_tb_desc.brsp.qos_null[tid].pbd;
    01377         thd = &he_tb_desc.brsp.qos_null[tid].thd;
    01378
    01379         thd->upatterntx = TX_HEADER_DESC_PATTERN;
    01380         thd->frmlen = MAC_QOS_NULL_FRAME_SIZE + MAC_FCS_LEN;
    01381         thd->datastartptr = CPU2HW(hdr);
    01382         thd->dataendptr = (uint32_t)thd->datastartptr + sizeof_b(*hdr) - 1;
    01383         thd->first_pbd_ptr = CPU2HW(pbd);
    01384         thd->macctrlinfo1 = EXPECTED_ACK_NO_ACK;
    01385         pbd->upatterntx = TX_PAYLOAD_DESC_PATTERN;
    01386         pbd->datastartptr = CPU2HW(&he_tb_desc.brsp.qos_null[tid].qos_ctrl);
    01387         pbd->dataendptr = (uint32_t)pbd->datastartptr + 1;
    01388     }
    01389 }
    01390
    01402 static void txl_he_tb_mpdu_transmit_trigger(struct txdesc *txdesc,
    01403                                             uint32_t txstatus)
    01404 {
    01405     struct he_trigger_tag *he_tb = &txl_he_env.trigger;
    01406     uint8_t access_category = he_tb->ac;
    01407     struct txl_list *txlist = &txl_cntrl_env.txlist[access_category];
    01408     struct mu_edca_param_tag *mu_edca_param = &txl_he_env.mu_edca.params[access_category];
    01409     struct tx_agg_desc *agg_desc = txdesc->lmac.agg_desc;
    01410     struct tx_hd *txhd = &txdesc->lmac.hw_desc->thd;
    01411
    01412     // Check HW status - In case of HE TB a successful status does not automatically mean
    01413     // that the MPDU was correctly acknowledged.
    01414     // Indeed we can receive a multi-STA BA in response, which is enough for HW to
    01415     // consider the MPDU transmission as successful, but this multi-STA BA may not
    01416     // include acknowledgment information for our device. Additional checks are therefore
    01417     // required.
    01418     if (txstatus & FRAME_SUCCESSFUL_TX_BIT)
    01419     {
    01420         if (he_tb->uora)
    01421             // HE TB transmission is considered successful in the selected RA-RU
    01422             nxmac_e_ocw_setf(txl_he_env.uora.eocw_min);
    01423         else
    01424             // Restart the MU EDCA for this access category
    01425             txl_he_mu_edca_start(he_tb->ac);
    01426
    01427         // Get possibly received BA frame
    01428         rxl_immediate_frame_get();
    01429     }
    01430     else
    01431     {
    01432         if (he_tb->uora)
    01433         {
    01434             // HE TB transmission in RA-RU is unsuccessful
    01435             uint8_t new_eocw = nxmac_e_ocw_getf();
    01436             new_eocw = new_eocw + 1;
    01437
    01438             if (new_eocw > txl_he_env.uora.eocw_max)
    01439                 new_eocw = txl_he_env.uora.eocw_max;
    01440
    01441             nxmac_e_ocw_setf(new_eocw);
    01442         }
    01443     }
    01444
    01445     // If we did not get any BA, we need to pop the descriptor here
    01446     if (!(agg_desc->status & AGG_BA_RECEIVED))
    01447     {
    01448         // Pop the aggregate descriptor from the list
    01449         co_list_pop_front(&txlist->aggregates);
    01450     }
    01451     else if (!(agg_desc->status & AGG_BA_VALID))
    01452     {
    01453         // We received a multi-STA BA, but it does not contain any acknowledgment for us
    01454         txhd->statinfo &= ~FRAME_SUCCESSFUL_TX_BIT;
    01455         txstatus &= ~FRAME_SUCCESSFUL_TX_BIT;
    01456     }
    01457
    01458     // Release the A-MPDU descriptor immediately, because in case of singleton it is used
    01459     // only for the BA reception handling, but not during the confirmation phase
    01460     txl_agg_release(agg_desc);
    01461     txdesc->lmac.agg_desc = NULL;
    01462
    01463     // Check if we need to retry the MPDU
    01464     if (!(txstatus & FRAME_SUCCESSFUL_TX_BIT))
    01465     {
    01466         uint32_t nb_retry = (txstatus & NUM_MPDU_RETRIES_MSK) >> NUM_MPDU_RETRIES_OFT;
    01467         bool amsdu = false;
    01468
    01469         #if NX_AMSDU_TX
    01470         // Check if this packet is split across several buffers, because if this is the
    01471         // case we cannot do the retry as some of the buffers have already been freed
    01472         // from shared memory. The retries in such case are performed as part of the BA
    01473         // agreement which is established (A-MSDUs are used only if a BA agreement is in
    01474         // place)
    01475         if (txl_buffer_is_amsdu_multi_buf(txdesc))
    01476             amsdu = true;
    01477         #endif
    01478
    01479         if (!amsdu && (nb_retry < 5))
    01480         {
    01481             struct txl_buffer_control *bufctrl = txl_buffer_control_get(txdesc);
    01482
    01483             // For the first retransmission, let's copy (maybe again) the policy table
    01484             // in the buffer, as it might not be present if the MPDU was initially
    01485             // supposed to be transmitted inside an A-MPDU.
    01486             if (!nb_retry)
    01487             {
    01488                 #if NX_UMAC_PRESENT
    01489                 // Copy the buffer control
    01490                 txl_buffer_control_copy(txdesc, txl_buffer_get(txdesc));
    01491                 #endif
    01492
    01493                 // Check if the singleton shall be protected with a RTS/CTS
    01494                 txl_he_txop_dur_rtscts_thres_mpdu_check(txdesc);
    01495             }
    01496
    01497             nb_retry++;
    01498             txhd->macctrlinfo1 = bufctrl->mac_control_info;
    01499             txhd->phyctrlinfo = bufctrl->phy_control_info;
    01500             txhd->policyentryaddr = CPU2HW(&bufctrl->policy_tbl);
    01501             txhd->statinfo = nb_retry << NUM_MPDU_RETRIES_OFT;
    01502
    01503             // Chain the retransmission at the head of the list, because it shall be
    01504             // the next packet transmitted in this access category, in order to ensure
    01505             // correct ordering in case no BA agreement is setup
    01506             if (mu_edca_param->first_frame_exch)
    01507                 txhd->nextfrmexseq_ptr = CPU2HW(mu_edca_param->first_frame_exch);
    01508             else
    01509                 txlist->last_frame_exch = txhd;
    01510             mu_edca_param->first_frame_exch = txhd;
    01511
    01512             // Increase by one the PPDU count because the current packet is retried, and
    01513             // this counter will be decreased later in the processing
    01514             txlist->ppdu_cnt++;
    01515             return;
    01516         }
    01517         else
    01518         {
    01519             // We reached the retry limit, let's indicate it to the upper layers
    01520             txhd->statinfo |= RETRY_LIMIT_REACHED_BIT;
    01521         }
    01522     }
    01523
    01524     #if !NX_FULLY_HOSTED
    01525     // Free the MPDU buffers and allocate buffer(s) for the subsequent ones
    01526     txl_free_done_mpdu(txdesc, access_category, 0);
    01527     #endif
    01528
    01529     // Pop picked txdesc definitively from list
    01530     co_list_pop_front(&(txlist->transmitting[0]));
    01531
    01532     #if NX_TX_FRAME
    01533     // Check if the frame was generated internally
    01534     if (is_int_frame(txdesc))
    01535     {
    01536         // Put the descriptor in the CFM queue
    01537         txl_frame_cfm(txdesc);
    01538     }
    01539     else
    01540     #endif
    01541     {
    01542         // Put the descriptor in the CFM queue
    01543         txl_cfm_push(txdesc, txstatus, access_category);
    01544     }
    01545 }
    01546
    01555 static void txl_he_tb_ampdu_mpdu_transmit_trigger(struct txdesc *txdesc,
    01556                                                   uint32_t txstatus)
    01557 {
    01558     struct he_trigger_tag *he_tb = &txl_he_env.trigger;
    01559     uint8_t access_category = he_tb->ac;
    01560     struct txl_list *txlist = &txl_cntrl_env.txlist[access_category];
    01561
    01562     #if !NX_FULLY_HOSTED
    01563     // Free the MPDU buffers and allocate buffer(s) for the subsequent ones
    01564     txl_free_done_mpdu(txdesc, access_category, 0);
    01565     #endif
    01566
    01567     // Pop picked txdesc definitively from list
    01568     co_list_pop_front(&(txlist->transmitting[0]));
    01569
    01570     // Put the descriptor in the CFM queue
    01571     txl_cfm_push(txdesc, txstatus, access_category);
    01572
    01573     // At last MPDU in AMPDU, we stop pushing CFMs until BAR status done;
    01574     // Keep last mpdu pointer
    01575     if (is_mpdu_last(txdesc))
    01576     {
    01577         txlist->agg_desc = txdesc->lmac.agg_desc;
    01578         txlist->chk_state = ATHD_CHK_STATE;
    01579     }
    01580 }
    01581
    01582 void txl_he_bsr_compute(struct vif_info_tag *vif)
    01583 {
    01584     #if NX_UMAC_PRESENT
    01585     uint32_t bsr, buffered, buffered_all = 0, buffered_aci_high = 0;
    01586     uint8_t aci_bitmap = 0, delta_tid = 0, tids_nb = 0;
    01587     uint8_t aci_bitmap_set = 0, aci_high = 0, tid;
    01588     uint8_t qs_high = 0, qs_all, sf;
    01589     uint32_t buffered_per_aci[AC_MAX];
    01590     struct sta_info_tag *sta;
    01591
    01592     // Check if VIF is of type STA and active
    01593     if ((vif->type != VIF_STA) || !vif->active)
    01594         return;
    01595
    01596     // Get STA information
    01597     sta = &sta_info_tab[vif->u.sta.ap_id];
    01598     if (!sta->valid || !STA_CAPA(sta, HE))
    01599         return;
    01600
    01601     // Compute BSR
    01602     bsr = MAC_HTC_TYPE_HE | (MAC_HTC_HE_CTRL_ID_BSR << MAC_HTC_HE_A_CONTROL_OFT);
    01603
    01604     memset(buffered_per_aci, 0, sizeof(buffered_per_aci));
    01605     for (tid = 0; tid < TID_MGT; tid++)
    01606     {
    01607         uint8_t aci = mac_ac2aci[mac_tid2ac[tid]];
    01608         buffered = macif_buffered_get(sta->staid, tid);
    01609         if (!buffered)
    01610             continue;
    01611
    01612         tids_nb++;
    01613
    01614         // Check whether the amount of buffered data for this TID is higher than the max
    01615         // we can code in the BSR - If this is the case, limit it to this size, as this
    01616         // will ensure there is no overflow of the 32-bit variables used in the
    01617         // computation
    01618         if (buffered > BSR_BUFFERED_MAX)
    01619             buffered = BSR_BUFFERED_MAX;
    01620
    01621         buffered_all += buffered;
    01622         buffered_per_aci[aci] += buffered;
    01623
    01624         // Check whether the current ACI is the one having the more buffered data
    01625         if (buffered_per_aci[aci] > buffered_aci_high)
    01626         {
    01627             buffered_aci_high = buffered_per_aci[aci];
    01628             aci_high = aci;
    01629         }
    01630
    01631         // Check if the bit is already set
    01632         if (CO_BIT(aci) & aci_bitmap)
    01633             continue;
    01634
    01635         // Set ACI in bitmap
    01636         aci_bitmap |= CO_BIT(aci);
    01637         aci_bitmap_set++;
    01638     }
    01639
    01640     if (tids_nb == TID_MGT)
    01641     {
    01642         aci_bitmap = 0;
    01643         delta_tid = 3;
    01644     }
    01645     else
    01646         delta_tid = tids_nb - aci_bitmap_set;
    01647
    01648     sf = txl_he_bsr_get_sf_and_qsize(buffered_all, buffered_aci_high, &qs_all, &qs_high);
    01649
    01650     bsr |= aci_bitmap << (MAC_HTC_HE_BSR_ACI_BMP_OFT + MAC_HTC_HE_A_CONTROL_OFT);
    01651     bsr |= delta_tid << (MAC_HTC_HE_BSR_DELTA_TID_OFT + MAC_HTC_HE_A_CONTROL_OFT);
    01652     bsr |= aci_high << (MAC_HTC_HE_BSR_ACI_HIGH_OFT + MAC_HTC_HE_A_CONTROL_OFT);
    01653     bsr |= sf << (MAC_HTC_HE_BSR_SCALING_FAC_OFT + MAC_HTC_HE_A_CONTROL_OFT);
    01654     bsr |= qs_high << (MAC_HTC_HE_BSR_QSIZE_HIGH_OFT + MAC_HTC_HE_A_CONTROL_OFT);
    01655     bsr |= qs_all << (MAC_HTC_HE_BSR_QSIZE_ALL_OFT + MAC_HTC_HE_A_CONTROL_OFT);
    01656
    01657     sta->bsr = bsr;
    01658     #endif
    01659 }
    01660
    01661 void txl_he_tb_transmit_cancelled(void)
    01662 {
    01663     uint8_t access_category;
    01664     struct txl_list *txlist;
    01665     struct txdesc *txdesc;
    01666     struct tx_agg_desc *agg_desc;
    01667     struct mu_edca_param_tag *mu_edca_param;
    01668
    01669     // Halt the HE TB HW queue in order to ensure that the HW does not restart the same
    01670     // HE TB PPDU transmission upon the next trigger frame reception
    01671     txl_he_tb_halt_queue();
    01672
    01673     // If only QoS-Null or BSRP response has been programmed, no need to free anything
    01674     if (!txl_he_env.tb_ongoing)
    01675         return;
    01676
    01677     access_category = txl_he_env.trigger.ac;
    01678     txlist = &txl_cntrl_env.txlist[access_category];
    01679     mu_edca_param = &txl_he_env.mu_edca.params[access_category];
    01680
    01681     PROF_TX_MAC_IRQ_SET();
    01682     PROF_TX_AC_IRQ_SET(access_category);
    01683
    01684     // Pick first TX descriptor in the transmitting list
    01685     txdesc = (struct txdesc *)co_list_pick(&(txlist->transmitting[0]));
    01686
    01687     // Here we check if the next TX descriptor for which the buffer has to be allocated
    01688     // and downloaded is part of the A-MPDU sent in this HE TB PPDU. If this is the case,
    01689     // and because this HE TB PPDU won't be transmitted, we move the first_to_download
    01690     // pointer to the TX descriptor immediately following the last one sent in the HE TB
    01691     // PPDU. This avoids spending time to allocate, format and free buffers that will
    01692     // anyway not be transmitted - Do this only if we are in the THD check state, i.e. if
    01693     // we programmed some data MPDUs that were not transmitted because the HE TB is
    01694     // cancelled. If we programmed a BAR in the HE TB, we shall not enter into this code
    01695     if (txlist->chk_state == THD_CHK_STATE)
    01696     {
    01697         agg_desc = txdesc->lmac.agg_desc;
    01698         if (is_mpdu_agg(txdesc) && (txlist->first_to_download[0]->lmac.agg_desc == agg_desc))
    01699         {
    01700             txlist->first_to_download[0] = tx_desc_next(agg_desc->txdesc_last);
    01701         }
    01702     }
    01703
    01704     // Walk through the list of SW descriptors programmed in the HE TB, and free them all
    01705     while (1)
    01706     {
    01707         //-----------------------
    01708         // MPDU THD status check
    01709         //-----------------------
    01710         if (txlist->chk_state == THD_CHK_STATE)
    01711         {
    01712             struct tx_hd *txhd;
    01713             uint32_t txstatus;
    01714
    01715             // Sanity check - When handling HE TB we should never reach a point where
    01716             // we don't have descriptors available anymore
    01717             ASSERT_ERR(txdesc != NULL);
    01718
    01719             txhd = &txdesc->lmac.hw_desc->thd;
    01720
    01721             // Set the done bit manually but not the success bit, as if the frame would
    01722             // have been transmitted but not acknowledged
    01723             txhd->statinfo |= HE_TB_TX_BIT | DESC_DONE_TX_BIT;
    01724             txstatus = txhd->statinfo;
    01725
    01726             // Manage singleton case
    01727             if (!is_mpdu_agg(txdesc))
    01728             {
    01729                 txl_he_tb_mpdu_transmit_trigger(txdesc, txstatus);
    01730                 break;
    01731             }
    01732
    01733             // Otherwise manage A-MPDU sub-frame case
    01734             txl_he_tb_ampdu_mpdu_transmit_trigger(txdesc, txstatus);
    01735
    01736             // Get next txdesc in transmitting list
    01737             txdesc = (struct txdesc *)co_list_pick(&(txlist->transmitting[0]));
    01738
    01739         }
    01740         //-----------------------
    01741         // A-THD status check
    01742         //-----------------------
    01743         else
    01744         {
    01745             //get the last txdesc queued into cfm list for this ac, its agg_desc and then bar_desc
    01746             struct tx_agg_desc *agg_desc = txlist->agg_desc;
    01747
    01748             // For profiling
    01749             PROF_AGG_BAR_DONETX_SET();
    01750
    01751             // Mark aggregate as ready for confirmation, without any BA received
    01752             agg_desc->status |= AGG_DONE;
    01753
    01754             // Pop the aggregate descriptor from the list
    01755             co_list_pop_front(&txlist->aggregates);
    01756
    01757             // Set an event to handle the confirmation of the queued aggregated MPDU in background
    01758             ke_evt_set(txl_cfm_evt_bit[access_category]);
    01759
    01760             // Change state back to MPDUs check
    01761             txlist->chk_state = THD_CHK_STATE;
    01762             txlist->agg_desc = NULL;
    01763
    01764             // For profiling
    01765             PROF_AGG_BAR_DONETX_CLR();
    01766             break;
    01767         }
    01768     }
    01769
    01770     // Re-configure the HW AC queue with the next packet to transmit
    01771     if (!txl_he_is_edca_off(access_category) && (mu_edca_param->first_frame_exch != NULL))
    01772     {
    01773         txl_cntrl_newhead(CPU2HW(mu_edca_param->first_frame_exch), access_category);
    01774     }
    01775
    01776     // Clear the TX activity timeout
    01777     txl_he_tb_timer_clear();
    01778
    01779     // We have one PPDU less in the TX path
    01780     txlist->ppdu_cnt--;
    01781
    01782     // Check if we need to close a pending A-MPDU
    01783     txl_agg_check(access_category);
    01784
    01785     PROF_TX_MAC_IRQ_CLR();
    01786 }
    01787
    01788 void txl_he_tb_transmit_trigger(void)
    01789 {
    01790     uint8_t access_category = txl_he_env.trigger.ac;
    01791     struct txl_list *txlist = &txl_cntrl_env.txlist[access_category];
    01792     struct he_trigger_tag *he_tb = &txl_he_env.trigger;
    01793     struct mu_edca_param_tag *mu_edca_param = &txl_he_env.mu_edca.params[access_category];
    01794
    01795     PROF_TX_MAC_IRQ_SET();
    01796     PROF_TX_AC_IRQ_SET(access_category);
    01797
    01798     // Walk through the list of completed SW descriptors
    01799     while (1)
    01800     {
    01801         struct txdesc * txdesc = NULL;
    01802
    01803         //-----------------------
    01804         // MPDU THD status check
    01805         //-----------------------
    01806         if (txlist->chk_state == THD_CHK_STATE)
    01807         {
    01808             struct tx_hd *txhd;
    01809             uint32_t txstatus;
    01810
    01811             //pick first txdesc in transmitting list to check its doneTx status
    01812             txdesc = (struct txdesc *)co_list_pick(&(txlist->transmitting[0]));
    01813
    01814             // Sanity check - When handling HE TB we should never reach a point where
    01815             // we don't have descriptors available anymore
    01816             ASSERT_ERR(txdesc != NULL);
    01817
    01818             txhd = &txdesc->lmac.hw_desc->thd;
    01819
    01820             // Check if HW handled this MPDU
    01821             if (!(txhd->statinfo & DESC_DONE_TX_BIT))
    01822             {
    01823                 #if !NX_FULLY_HOSTED && NX_AMSDU_TX
    01824                 // Maybe some A-MSDU subframes (i.e. TBD) are done, check that
    01825                 txl_check_done_amsdu_subframe(txdesc, access_category, 0);
    01826                 #endif
    01827                 // MPDU not yet transmitted, stop here and come back later
    01828                 PROF_TX_MAC_IRQ_CLR();
    01829                 return;
    01830             }
    01831
    01832             // Frame was sent in a HE TB PPDU
    01833             txhd->statinfo |= HE_TB_TX_BIT;
    01834             txstatus = txhd->statinfo;
    01835
    01836             // Manage singleton case
    01837             if (!is_mpdu_agg(txdesc))
    01838             {
    01839                 txl_he_tb_mpdu_transmit_trigger(txdesc, txstatus);
    01840                 break;
    01841             }
    01842
    01843             // Otherwise manage A-MPDU sub-frame case
    01844             txl_he_tb_ampdu_mpdu_transmit_trigger(txdesc, txstatus);
    01845         }
    01846         //-----------------------
    01847         // A-THD/BAR THD status check
    01848         //-----------------------
    01849         else
    01850         {
    01851             //get the last txdesc queued into cfm list for this ac, its agg_desc and then bar_desc
    01852             struct tx_agg_desc *agg_desc = txlist->agg_desc;
    01853             struct tx_hd *thd;
    01854             uint32_t thd_status;
    01855
    01856             if (txlist->chk_state == ATHD_CHK_STATE)
    01857                 // Get the A-THD descriptor
    01858                 thd = &agg_desc->a_thd;
    01859             else
    01860                 // Get the BAR THD descriptor
    01861                 thd = &agg_desc->bar_thd;
    01862
    01863             thd_status = thd->statinfo;
    01864             //BAR status is updated received
    01865             if (!(thd_status & DESC_DONE_TX_BIT))
    01866             {
    01867                 PROF_TX_MAC_IRQ_CLR();
    01868                 return;
    01869             }
    01870
    01871             // For profiling
    01872             PROF_AGG_BAR_DONETX_SET();
    01873
    01874             if (thd_status & FRAME_SUCCESSFUL_TX_BIT)
    01875             {
    01876                 // Check if BA has already been received
    01877                 if (!(agg_desc->status & AGG_BA_RECEIVED))
    01878                 {
    01879                     int i = 0;
    01880                     // Make a call to the RX path to get the BA that is
    01881                     // available, waiting for the RX timer to expire
    01882                     do
    01883                     {
    01884                         rxl_immediate_frame_get();
    01885                         i++;
    01886                     } while ((i < 5) && (!(agg_desc->status & AGG_BA_RECEIVED)));
    01887                 }
    01888
    01889                 // Sanity check - The BA shall now be available
    01890                 ASSERT_REC(agg_desc->status & AGG_BA_RECEIVED);
    01891
    01892                 if (he_tb->uora)
    01893                     // HE TB PPDU transmission is considered successful in the selected RA-RU
    01894                     nxmac_e_ocw_setf(txl_he_env.uora.eocw_min);
    01895                 else
    01896                     // Restart the MU EDCA for this access category
    01897                     txl_he_mu_edca_start(txl_he_env.trigger.ac);
    01898             }
    01899             else
    01900             {
    01901                 // Pop the aggregate descriptor from the list
    01902                 co_list_pop_front(&txlist->aggregates);
    01903
    01904                 if (he_tb->uora)
    01905                 {
    01906                     // HE TB PPDU transmission in RA-RU is unsuccessful
    01907                     uint8_t new_eocw = nxmac_e_ocw_getf();
    01908                     new_eocw = new_eocw + 1;
    01909
    01910                     if (new_eocw > txl_he_env.uora.eocw_max)
    01911                         new_eocw = txl_he_env.uora.eocw_max;
    01912
    01913                     nxmac_e_ocw_setf(new_eocw);
    01914                 }
    01915             }
    01916
    01917             // Mark aggregate as ready for confirmation
    01918             agg_desc->status |= AGG_DONE;
    01919
    01920             // Set an event to handle the confirmation of the queued aggregated MPDU in background
    01921             ke_evt_set(txl_cfm_evt_bit[access_category]);
    01922
    01923             //bar has been handled, BA reception status will be known at cfm,
    01924             //change state back to MPDUs check
    01925             txlist->chk_state = THD_CHK_STATE;
    01926             txlist->agg_desc = NULL;
    01927
    01928             // For profiling
    01929             PROF_AGG_BAR_DONETX_CLR();
    01930             break;
    01931         }
    01932     }
    01933
    01934     // Re-configure the HW AC queue with the next packet to transmit
    01935     if (!txl_he_is_edca_off(access_category) && (mu_edca_param->first_frame_exch != NULL))
    01936     {
    01937         txl_cntrl_newhead(CPU2HW(mu_edca_param->first_frame_exch), access_category);
    01938     }
    01939
    01940     // Clear the TX activity timeout
    01941     txl_he_tb_timer_clear();
    01942
    01943     // We have one PPDU less in the TX path
    01944     txlist->ppdu_cnt--;
    01945
    01946     // Check if we need to close a pending A-MPDU
    01947     txl_agg_check(access_category);
    01948
    01949     PROF_TX_MAC_IRQ_CLR();
    01950 }
    01951
    01952 void txl_he_init(void)
    01953 {
    01954     memset(&txl_he_env, 0, sizeof(txl_he_env));
    01955
    01956     txl_he_tb_desc_init();
    01957
    01958     // By default, use a fixed value for UPH, until we get it from HW register
    01959     txl_he_env.trigger.uph = MAC_HTC_HE(HTC_HE_UPH_DEF);
    01960
    01961     #if NX_MAC_VER > 20
    01962     // Limit the MCS that we can transmit over HE TB (MCS11 if LDPC is supported, MCS9 otherwise)
    01963     if (phy_ldpc_tx_supported())
    01964         nxmac_max_mcs_in_hetb_setf(11);
    01965     else
    01966         nxmac_max_mcs_in_hetb_setf(9);
    01967     #endif
    01968 }
    01969
    01970 void txl_he_reset(void)
    01971 {
    01972     struct mu_edca_tag mu_edca;
    01973     struct vif_info_tag *tb_vif;
    01974
    01975     #if NX_UMAC_PRESENT && NX_BEACONING
    01976     struct sta_info_tag *trigged_sta;
    01977     bool trig_started = (txl_he_env.trig_timer.cb != NULL);
    01978
    01979     // Check if the HE trigger timer is started
    01980     if (trig_started)
    01981     {
    01982         // Save the trigger timer env variable
    01983         trigged_sta = txl_he_env.trig_timer.env;
    01984         // Extract it from the list of timers
    01985         mm_timer_clear(&txl_he_env.trig_timer);
    01986         trig_started = true;
    01987     }
    01988     #endif // NX_UMAC_PRESENT && NX_BEACONING
    01989
    01990     // Save the HE TB VIF pointer
    01991     tb_vif = txl_he_env.tb_vif;
    01992
    01993     // Save the MU EDCA parameters
    01994     if (tb_vif)
    01995     {
    01996         mu_edca = txl_he_env.mu_edca;
    01997         // Check if the MU EDCA operation is started
    01998         if (mu_edca.timer.cb != NULL)
    01999             // Extract it from the list of timers
    02000             mm_timer_clear(&txl_he_env.mu_edca.timer);
    02001     }
    02002
    02003     // Re-initialize the full HE environment
    02004     txl_he_init();
    02005
    02006     // Restore the HE TB VIF pointer
    02007     txl_he_env.tb_vif = tb_vif;
    02008
    02009     // Restore the MU EDCA parameters
    02010     if (tb_vif)
    02011     {
    02012         // Restore MU EDCA parameters
    02013         txl_he_env.mu_edca.valid = mu_edca.valid;
    02014         for (int i = 0; i < AC_MAX; i++)
    02015         {
    02016             txl_he_env.mu_edca.params[i].edca = mu_edca.params[i].edca;
    02017             txl_he_env.mu_edca.params[i].timeout = mu_edca.params[i].timeout;
    02018         }
    02019     }
    02020
    02021     #if NX_UMAC_PRESENT && NX_BEACONING
    02022     // Check if the HE trigger timer has to be re-started
    02023     if (trig_started)
    02024     {
    02025         // Restart it
    02026         txl_he_start_trigger_scheduler(trigged_sta);
    02027     }
    02028     #endif // NX_UMAC_PRESENT && NX_BEACONING
    02029 }
    02030
    02031 bool txl_he_decode_m_ba(struct rxdesc *badesc, struct tx_agg_desc *agg_desc)
    02032 {
    02033     struct sta_info_tag *sta = &sta_info_tab[agg_desc->sta_idx];
    02034     struct rx_dmadesc *dma_hdrdesc = rxl_dmadesc_get(badesc);
    02035     struct rx_hd *hdrdesc = &dma_hdrdesc->hd;
    02036     struct rx_pbd *pd = HW2CPU(hdrdesc->first_pbd_ptr);
    02037     struct ba_base *ba_payl = (struct ba_base *)HW2CPU(pd->datastartptr);
    02038     struct ba_msta_aid_tid_info *aid_tid_info;
    02039     int remaining_len = hdrdesc->frmlen;
    02040     bool addr1_match = (hdrdesc->statinfo & RX_HD_ADDRMIS) == 0;
    02041     bool addr1_group = (hdrdesc->statinfo & RX_HD_GA_FRAME) != 0;
    02042
    02043     // Multi-STA BA can be unicast to our device or broadcast
    02044     if (!addr1_match && !addr1_group)
    02045         return false;
    02046
    02047     aid_tid_info = (struct ba_msta_aid_tid_info *)(ba_payl + 1);
    02048     remaining_len -= sizeof_b(struct ba_base);
    02049
    02050     // Go through the AID/TID tuples
    02051     while (remaining_len >= 2)
    02052     {
    02053         uint16_t aid = (aid_tid_info->aid_tid & BA_MULTI_STA_AID_MSK) >> BA_MULTI_STA_AID_OFT;
    02054         int aid_tid_len = txl_he_m_ba_aid_tid_len(aid_tid_info, remaining_len);
    02055
    02056         if (aid_tid_len < 0)
    02057             return false;
    02058
    02059         // Check if the current AID matches ours
    02060         if (aid == sta->aid)
    02061         {
    02062             uint8_t tid;
    02063
    02064             if (aid_tid_info->aid_tid & BA_MULTI_STA_ACK_BIT)
    02065             {
    02066                 agg_desc->ssc_bitmap = NULL;
    02067                 return true;
    02068             }
    02069
    02070             tid = (aid_tid_info->aid_tid & BA_MULTI_STA_TID_MSK) >> BA_MULTI_STA_TID_OFT;
    02071
    02072             // Check if both TID match
    02073             if (tid != agg_desc->tid)
    02074                 // No match, we consider BA as invalid
    02075                 return false;
    02076
    02077             memcpy(&agg_desc->ssc_bitmap_tab, &aid_tid_info->ssc_bitmap,
    02078                    aid_tid_len - sizeof_b(aid_tid_info->aid_tid));
    02079             agg_desc->ssc_bitmap = (struct ba_ssc_bitmap *)(&agg_desc->ssc_bitmap_tab);
    02080             return true;
    02081         }
    02082
    02083         // Continue looping through the AID/TID tuples
    02084         aid_tid_info = HW2CPU(CPU2HW(aid_tid_info) + aid_tid_len);
    02085         remaining_len -= aid_tid_len;
    02086     };
    02087
    02088     // No match, we consider BA as invalid
    02089     return false;
    02090 }
    02091
    02092 void txl_he_trigger_push(struct rxdesc *rxdesc)
    02093 {
    02094     uint8_t sta_idx;
    02095     uint16_t key_idx_hw;
    02096     struct rx_dmadesc *dma_hdrdesc = rxl_dmadesc_get(rxdesc);
    02097     struct rx_hd *hdrdesc = &dma_hdrdesc->hd;
    02098     struct rx_pbd *pd = HW2CPU(hdrdesc->first_pbd_ptr);
    02099     uint32_t statinfo = hdrdesc->statinfo;
    02100     struct he_trigger_tag *he_tb = &txl_he_env.trigger;
    02101     struct sta_info_tag *sta;
    02102     struct vif_info_tag *vif;
    02103
    02104     // By default we consider the trigger frame as invalid
    02105     he_tb->trig_valid = false;
    02106
    02107     // Sanity checks - the HW is supposed to analyze the trigger frame, so we consider
    02108     // invalid frames as errors
    02109     ASSERT_REC(hdrdesc->frmlen >= HE_TRIG_FRM_MIN_LEN);
    02110
    02111     // Check if the sending STA is registered
    02112     if (!(statinfo & KEY_IDX_VALID_BIT))
    02113     {
    02114         MAC_ADDR_CPY(&he_tb->ta, HW2CPU(pd->datastartptr + MAC_HEAD_ADDR2_OFT));
    02115         return;
    02116     }
    02117
    02118     // Get the key index
    02119     key_idx_hw = (uint16_t)((statinfo & KEY_IDX_MSK) >> KEY_IDX_OFT);
    02120
    02121     // Sanity check
    02122     ASSERT_REC(key_idx_hw >= MM_SEC_DEFAULT_KEY_COUNT);
    02123
    02124     // Check if the peer STA is still active
    02125     sta_idx = (uint8_t)(key_idx_hw - MM_SEC_DEFAULT_KEY_COUNT);
    02126     sta = &sta_info_tab[sta_idx];
    02127     if (sta->valid)
    02128     {
    02129         he_tb->ta = sta->mac_addr;
    02130     }
    02131     else
    02132     {
    02133         MAC_ADDR_CPY(&he_tb->ta, HW2CPU(pd->datastartptr + MAC_HEAD_ADDR2_OFT));
    02134         return;
    02135     }
    02136
    02137     // Ensure we are aligned with the HE TB VIF
    02138     vif = &vif_info_tab[sta->inst_nbr];
    02139     if (vif != txl_he_env.tb_vif)
    02140         return;
    02141
    02142     // Ensure we will have enough time to program something
    02143     if (nxmac_tx_hetb_rem_dur_getf() < TX_HE_TB_PROG_MIN_TIME)
    02144         return;
    02145
    02146     // Compute the HE TB parameters
    02147     txl_he_tb_params_compute();
    02148
    02149     // Is trigger frame valid ? Today the we only check if we have enough resources in
    02150     // the HE TB to send at least a QoS-NULL frame
    02151     he_tb->trig_valid = (he_tb->max_len >= TX_HE_TB_MIN_PSDU_LEN)?true:false;
    02152
    02153     // Fill HE TB information structure
    02154     he_tb->sta = sta;
    02155
    02156     // Update RC about received trigger frame
    02157     txl_he_tb_set_rc_info();
    02158 }
    02159
    02160 void txl_he_tb_prot_trigger(void)
    02161 {
    02162     // For profiling
    02163     PROF_TX_HE_TRIG_IRQ_SET();
    02164
    02165     // Call the RX path to retrieve the trigger frame
    02166     rxl_immediate_frame_get();
    02167
    02168     // Send the HE TB PPDU based on the received trigger frame
    02169     txl_he_tb_ppdu_send();
    02170
    02171     // For profiling
    02172     PROF_TX_HE_TRIG_IRQ_CLR();
    02173 }
    02174
    02175 void txl_he_tb_config(void)
    02176 {
    02177     struct vif_info_tag *vif = vif_mgmt_get_single_sta_vif();
    02178
    02179     // Check if HE is supported by the MAC HW and PHY
    02180     if (hal_machw_he_support() && (vif != NULL))
    02181     {
    02182         // Save TB VIF pointer
    02183         txl_he_env.tb_vif = vif;
    02184
    02185         // Enable the HE TB operation
    02186         txl_he_tb_enable();
    02187     }
    02188     else
    02189     {
    02190         // Disable the HE TB operation
    02191         txl_he_tb_disable();
    02192
    02193         // Clear TB VIF pointer
    02194         txl_he_env.tb_vif = NULL;
    02195     }
    02196 }
    02197
    02198 void txl_he_tb_enable(void)
    02199 {
    02200     struct tx_policy_tbl *pol;
    02201     uint8_t hw_key_idx;
    02202
    02203     if (txl_he_env.tb_vif == NULL || !txl_he_env.tb_vif->active)
    02204         return;
    02205
    02206     // Compute MAC control information fields of the HE TB policy table
    02207     pol = &he_tb_desc.tb_pol;
    02208     hw_key_idx = MM_STA_TO_KEY(txl_he_env.tb_vif->u.sta.ap_id);
    02209     pol->maccntrlinfo1 = (hw_key_idx << KEYSRAM_INDEX_RA_OFT) | hw_key_idx;
    02210     pol->maccntrlinfo2 = 0xFFFF0704;
    02211
    02212     // Enable TB protocol interrupts
    02213     nxmac_enable_tb_prot_trigger_setf(1);
    02214     nxmac_enable_tb_tx_trigger_setf(1);
    02215     nxmac_enable_tb_tx_cancelled_setf(1);
    02216     #if NX_AMSDU_TX
    02217     nxmac_enable_tb_tx_buf_trigger_setf(1);
    02218     #endif
    02219     nxmac_accept_trigger_sw_frames_setf(1);
    02220     nxmac_ra_ru_enable_setf(1);
    02221     nxmac_ra_ru_type_setf(0);
    02222
    02223 }
    02224
    02225 void txl_he_tb_disable(void)
    02226 {
    02227     if (txl_he_env.tb_vif != NULL)
    02228         // Disable the MU EDCA operation
    02229         txl_he_mu_edca_stop();
    02230
    02231     // Disable TB protocol interrupts
    02232     nxmac_accept_trigger_sw_frames_setf(0);
    02233     nxmac_enable_tb_prot_trigger_setf(0);
    02234     nxmac_enable_tb_tx_trigger_setf(0);
    02235     nxmac_enable_tb_tx_cancelled_setf(0);
    02236     #if NX_AMSDU_TX
    02237     nxmac_enable_tb_tx_buf_trigger_setf(0);
    02238     #endif
    02239     nxmac_ra_ru_enable_setf(0);
    02240 }
    02241
    02242 #if NX_UMAC_PRESENT
    02243 uint32_t txl_he_htc_get(struct txdesc *txdesc, struct sta_info_tag *sta)
    02244 {
    02245     struct tx_agg_desc *agg_desc = txdesc->lmac.agg_desc;
    02246
    02247     // Check if we are sending the frame in a HE TB PPDU or not
    02248     if (agg_desc && ((agg_desc->status & AGG_TB) != 0))
    02249         // HE TB PPDU - We shall put the UPH control field
    02250         return txl_he_env.trigger.uph;
    02251
    02252     // HE SU case - We shall put the BSR control field
    02253     return sta->bsr;
    02254 }
    02255 #endif
    02256
    02257 uint32_t txl_he_idx_to_32us_len_get(int base_idx, uint8_t bw)
    02258 {
    02259     int idx = base_idx + 3 * (bw >> 1);
    02260     int shift = bw & 0x01;
    02261     return (((uint32_t)TX_HE_RATE_TO_32US_LEN[idx]) << shift);
    02262 }
    02263
    02264 uint16_t txl_he_idx_to_1us_len_get(int base_idx, uint8_t bw)
    02265 {
    02266     int idx = base_idx + 3 * (bw >> 1);
    02267     int shift = bw & 0x01;
    02268     return (((uint32_t)TX_HE_RATE_TO_MIN_SEP[idx]) << shift);
    02269 }
    02270
    02271 int txl_he_ampdu_param_get(struct txdesc *txdesc,
    02272                            uint8_t format_mod,
    02273                            uint32_t *max_len_sta,
    02274                            uint32_t *nss)
    02275 {
    02276     uint32_t phy_flags = txdesc->umac.phy_flags;
    02277     uint32_t mcs_idx = (phy_flags & MCS_INDEX_TX_RCX_MASK) >> MCS_INDEX_TX_RCX_OFT;
    02278     uint32_t gi = (phy_flags & HE_GI_TYPE_TX_RCX_MASK) >> HE_GI_TYPE_TX_RCX_OFT;
    02279     struct sta_info_tag *sta = &sta_info_tab[txdesc->host.staid];
    02280
    02281     // Only HE SU for now
    02282     ASSERT_ERR(format_mod == FORMATMOD_HE_SU);
    02283
    02284     // Extract NSS
    02285     *nss = ((mcs_idx & VHT_NSS_MASK) >> VHT_NSS_OFT) + 1;
    02286
    02287     // Extract MCS index
    02288     mcs_idx = (mcs_idx & VHT_MCS_MASK) >> VHT_MCS_OFT;
    02289
    02290     // Sanity checks: Maximum 4 SS supported, and MCS shall be between 0 and 11
    02291     ASSERT_ERR((*nss > 0) && (*nss <= 4));
    02292     ASSERT_ERR(mcs_idx <= 11);
    02293
    02294     // Get the maximum HE A-MPDU size supported by the receiver
    02295     *max_len_sta = sta->ampdu_size_max_he;
    02296
    02297     // To compute the maximum length we take the minimal bandwidth, to ensure that the
    02298     // packet won't cross the L-SIG duration limit in case the MAC HW would have to
    02299     // reduce the transmission bandwidth
    02300     return (mcs_idx * 6 + gi);
    02301 }
    02302
    02303 void txl_he_mu_edca_param_set(struct mm_set_mu_edca_req const *param)
    02304 {
    02305     struct mu_edca_tag *mu_edca = &txl_he_env.mu_edca;
    02306
    02307     // Go through the different access categories
    02308     for (int i = 0; i < AC_MAX; i++)
    02309     {
    02310         uint8_t aifsn = param->param[i] & 0x0000000F;
    02311         uint8_t timeout = (param->param[i] & 0x00FF0000) >> 16;
    02312         uint16_t cw = (param->param[i] & 0x0000FF00) >> 4;
    02313
    02314         mu_edca->params[i].timeout = timeout;
    02315         mu_edca->params[i].edca = cw | aifsn;
    02316         // Check if a HE TB is enabled
    02317         if (txl_he_env.tb_vif)
    02318         {
    02319             // Keep TXOP as advertised in WMM parameter element
    02320             mu_edca->params[i].edca |= txl_he_env.tb_vif->txq_params[i] & 0xFFFFF000;
    02321         }
    02322     }
    02323
    02324     // MU EDCA parameters are now valid
    02325     mu_edca->valid = true;
    02326 }
    02327
    02328 void txl_he_uora_param_set(struct mm_set_uora_req const *param)
    02329 {
    02330     struct uora_tag *uora = &txl_he_env.uora;
    02331
    02332     uora->eocw_min = param->eocw_min;
    02333     uora->eocw_max = param->eocw_max;
    02334 }
    02335
    02336 void txl_he_mu_edca_blocked(struct tx_hd *thd, uint8_t ac)
    02337 {
    02338     struct mu_edca_tag *mu_edca = &txl_he_env.mu_edca;
    02339     struct mu_edca_param_tag *mu_edca_param = &txl_he_env.mu_edca.params[ac];
    02340
    02341     // Check if we have valid MU EDCA parameters available
    02342     if (mu_edca->timer.cb)
    02343     {
    02344         // If EDCA is off remind the head of the EDCA queue
    02345         if (txl_he_is_edca_off(ac))
    02346             mu_edca_param->first_frame_exch = thd;
    02347
    02348         // Decrease MU EDCA timer so that EDCA is re-started on next tick
    02349         mu_edca_param->timer = 1;
    02350     }
    02351 }
    02352
    02353 #if NX_UMAC_PRESENT && NX_BEACONING
    02354 void txl_he_start_trigger_scheduler(struct sta_info_tag *sta)
    02355 {
    02356     txl_he_env.trig_timer.cb = txl_he_trig_time;
    02357     txl_he_env.trig_timer.env = sta;
    02358     mm_timer_set(&txl_he_env.trig_timer, hal_machw_time() + TX_HE_TRIG_PERIOD);
    02359 }
    02360 #endif // NX_UMAC_PRESENT && NX_BEACONING
    02361
    02362 void txl_he_txop_dur_rtscts_thres_ampdu_check(struct txdesc *txdesc)
    02363 {
    02364     struct vif_info_tag *vif = &vif_info_tab[txdesc->host.vif_idx];
    02365     struct tx_agg_desc *agg_desc = txdesc->lmac.agg_desc;
    02366
    02367     if (vif->txop_dur_rts_thres != MAC_HE_OPER_TXOP_DUR_RTS_THRES_DISABLED)
    02368     {
    02369         txl_he_txop_dur_rtscts_thres_apply(&txdesc->umac.phy_flags, agg_desc->a_thd.frmlen,
    02370                                            vif->txop_dur_rts_thres);
    02371     }
    02372 }
    02373
    02374 void txl_he_txop_dur_rtscts_thres_mpdu_check(struct txdesc *txdesc)
    02375 {
    02376     struct vif_info_tag *vif = &vif_info_tab[txdesc->host.vif_idx];
    02377     struct txl_buffer_control *bufctrl = txl_buffer_control_get(txdesc);
    02378     struct tx_hd *txhd = &txdesc->lmac.hw_desc->thd;
    02379     struct tx_policy_tbl *pt = &bufctrl->policy_tbl;
    02380
    02381     if (vif->txop_dur_rts_thres != MAC_HE_OPER_TXOP_DUR_RTS_THRES_DISABLED)
    02382     {
    02383         for (int i = 0; i < RATE_CONTROL_STEPS; i++)
    02384         {
    02385             txl_he_txop_dur_rtscts_thres_apply(&pt->ratecntrlinfo[i], txhd->frmlen,
    02386                                                vif->txop_dur_rts_thres);
    02387         }
    02388     }
    02389 }
    02390
    02391 #endif // NX_MAC_HE
    02392