- Main Page
- Modules
- Data Structures
- Files

- File List
- Globals

# /space/home/slher/rel/Beken/v6_4_5/macsw/ip/lmac/src/rx/rxl/v10/rxl_hwdesc.c

Go to the documentation of this file.

    00001
    00018 /*
    00019  * INCLUDE FILES
    00020  ****************************************************************************************
    00021  */
    00022 #include "rxl_hwdesc.h"
    00023
    00024 #include "ke_event.h"
    00025 #include "rxl_cntrl.h"
    00026 #if NX_UMAC_PRESENT
    00027 #include "rxu_cntrl.h"
    00028 #endif
    00029 #include "co_utils.h"
    00030 #include "macif.h"
    00031 #if NX_AMPDU_TX
    00032 #include "txl_cfm.h"
    00033 #endif
    00034 #if NX_MAC_HE
    00035 #include "txl_he.h"
    00036 #endif
    00037 #include "co_endian.h"
    00038 #include "reg_mac_pl.h"
    00039 #include "reg_mac_core.h"
    00040
    00041 /*
    00042  * TYPE DEFINITION
    00043  ****************************************************************************************
    00044  */
    00045
    00047 struct rxl_hwdesc_env_tag
    00048 {
    00050     struct co_list ready;
    00052     struct rx_dmadesc *first_dmadesc;
    00054     struct rx_dmadesc *last_dmadesc;
    00056     struct rx_dmadesc *free_dmadesc;
    00058     struct rx_pbd *first;
    00060     struct rx_pbd *last;
    00062     struct rx_pbd *free;
    00064     bool monitor_en;
    00065 };
    00066
    00067 /*
    00068  * VARIABLES
    00069  ****************************************************************************************
    00070  */
    00072 static struct rxdesc rx_swdesc_tab[NX_RXDESC_CNT];
    00073
    00075 static struct rxl_hwdesc_env_tag rx_hwdesc_env;
    00076
    00078 struct rx_dmadesc       rx_dma_hdrdesc[NX_RXDESC_CNT] __SHAREDRAM;
    00080 struct rx_payloaddesc   rx_payload_desc[NX_RX_PAYLOAD_DESC_CNT] __SHAREDRAM;
    00081
    00082 /*
    00083  * FUNCTION DEFINITIONS
    00084  ****************************************************************************************
    00085  */
    00096 static void rxl_hd_append(struct rx_dmadesc *desc)
    00097 {
    00098     struct rx_dmadesc *free_desc;
    00099
    00100     // sanity check: function can not be called with NULL
    00101     ASSERT_ERR(desc != NULL);
    00102
    00103     // check if the HW is still pointing to the spare descriptor
    00104     if (HW2CPU(nxmac_debug_rx_hdr_c_ptr_get()) == rx_hwdesc_env.free_dmadesc)
    00105     {
    00106         // The HW is still pointing to the spare descriptor, therefore we cannot release
    00107         // it now. Instead we release the current descriptor.
    00108         free_desc = desc;
    00109     }
    00110     else
    00111     {
    00112         // Otherwise we free the spare descriptor
    00113         free_desc = rx_hwdesc_env.free_dmadesc;
    00114
    00115         // Save the new free descriptor
    00116         rx_hwdesc_env.free_dmadesc = desc;
    00117     }
    00118
    00119     // clear the MPDU status info
    00120     free_desc->hd.statinfo = 0;
    00121
    00122     // reset the next pointer
    00123     free_desc->hd.next = 0;
    00124
    00125     // reset the first payload descriptor pointer
    00126     free_desc->hd.first_pbd_ptr = 0;
    00127
    00128     // reset the frame length field
    00129     free_desc->hd.frmlen = 0;
    00130
    00131     // Link the RHD to the current list and trigger a newTail
    00132     rx_hwdesc_env.last_dmadesc->hd.next = CPU2HW(&(free_desc->hd));
    00133     nxmac_dma_cntrl_set(NXMAC_RX_HEADER_NEW_TAIL_BIT);
    00134
    00135     // record the last pointer
    00136     rx_hwdesc_env.last_dmadesc = free_desc;
    00137
    00138     // check if we reached the end of the RX header descriptor list
    00139     if (rx_hwdesc_env.first_dmadesc == NULL)
    00140     {
    00141         rx_hwdesc_env.first_dmadesc = free_desc;
    00142     }
    00143 }
    00144
    00157 static void rxl_pd_append(struct rx_pbd *first, struct rx_pbd* last, struct rx_pbd* spare)
    00158 {
    00159     // sanity check: the function can not be called with NULL
    00160     ASSERT_ERR(spare != NULL);
    00161
    00162     // check if the HW is still pointing to the spare descriptor
    00163     if (HW2CPU(nxmac_debug_rx_pay_c_ptr_get()) == rx_hwdesc_env.free)
    00164     {
    00165         // The HW is still pointing to the spare descriptor, therefore we cannot release
    00166         // it now. Instead we release the current descriptor.
    00167         // Add the free element at the end of the list
    00168         if (last == NULL)
    00169         {
    00170             // No element in the list
    00171             first = spare;
    00172         }
    00173         last = spare;
    00174
    00175         // Reset the stat info
    00176         last->bufstatinfo = 0;
    00177     }
    00178     else
    00179     {
    00180         // Otherwise we free the spare descriptor
    00181         struct rx_pbd *free = rx_hwdesc_env.free;
    00182
    00183         // Save the new free descriptor
    00184         rx_hwdesc_env.free = spare;
    00185
    00186         // Add the free element at the end of the list
    00187         if (last == NULL)
    00188         {
    00189             // No element in the list
    00190             first = last = free;
    00191         }
    00192         else
    00193         {
    00194             free->next = CPU2HW(first);
    00195             first = free;
    00196         }
    00197
    00198         // Reset the stat info
    00199         first->bufstatinfo = 0;
    00200     }
    00201
    00202     // reset the next pointer
    00203     last->next = 0;
    00204
    00205     // Link the descriptors to the current list and trigger a newTail
    00206     rx_hwdesc_env.last->next = CPU2HW(first);
    00207     nxmac_dma_cntrl_set(NXMAC_RX_PAYLOAD_NEW_TAIL_BIT);
    00208
    00209     // record the last pointer
    00210     rx_hwdesc_env.last = last;
    00211
    00212     // check if the pointer to the first descriptor is NULL (debug and error logs only)
    00213     if (rx_hwdesc_env.first == NULL)
    00214     {
    00215         rx_hwdesc_env.first = first;
    00216     }
    00217 }
    00218
    00219 #if NX_AMSDU_DEAGG
    00220
    00236 static uint16_t rxl_amsdu_subframe_len_get(struct rx_payloaddesc *pd,
    00237                                            uint16_t payl_offset,
    00238                                            uint16_t mpdu_len)
    00239 {
    00240     uint16_t subfrm_len;
    00241     uint32_t subfrm_len_addr;
    00242
    00243     // Check if we still have at least the space for a A-MSDU subframe header in the MPDU
    00244     if (sizeof_b(struct amsdu_hdr) > mpdu_len)
    00245         return 0;
    00246
    00247     // Check if the A-MSDU subframe length is present in the current payload buffer
    00248     // or in the next one - Note that due to the A-MSDU subframe alignment in the MPDU,
    00249     // we are sure that the length field is not split across two payload descriptors,
    00250     // and we can do a 16-bit aligned read to get it
    00251     if (payl_offset + sizeof_b(struct amsdu_hdr) <= NX_RX_PAYLOAD_LEN)
    00252     {
    00253         subfrm_len_addr = pd->pbd.datastartptr + payl_offset + 2 * MAC_ADDR_LEN;
    00254     }
    00255     else
    00256     {
    00257         uint16_t offset = payl_offset + 2 * MAC_ADDR_LEN - NX_RX_PAYLOAD_LEN;
    00258         struct rx_payloaddesc *pd_tmp = (struct rx_payloaddesc *)HW2CPU(pd->pbd.next);
    00259
    00260         subfrm_len_addr = pd_tmp->pbd.datastartptr + offset;
    00261     }
    00262
    00263     // Read the length from the A-MSDU subframe header
    00264     subfrm_len = co_ntohs(co_read16(HW2CPU(subfrm_len_addr))) + sizeof_b(struct amsdu_hdr);
    00265
    00266     // Check if the A-MSDU subframe is valid
    00267     if ((subfrm_len > mpdu_len) || (subfrm_len > RX_MAX_AMSDU_SUBFRAME_LEN))
    00268         return 0;
    00269
    00270     // Check if some padding is present
    00271     if ((mpdu_len - subfrm_len) < 3)
    00272         // Last A-MSDU subframe, so we consider that the subframe length is the rest of
    00273         // the MPDU
    00274         subfrm_len = mpdu_len;
    00275     else
    00276         // Intermediate A-MSDU subframe, so correct the length by adding the padding
    00277         subfrm_len = CO_ALIGN4_HI(subfrm_len);
    00278
    00279     return subfrm_len;
    00280 }
    00281 #endif
    00282
    00292 static bool rxl_rxcntrl_frame(struct rxdesc* rxdesc)
    00293 {
    00294     bool handled = true;
    00295     struct rx_dmadesc *dma_hdrdesc = rxl_dmadesc_get(rxdesc);
    00296
    00297     // Check if we received a NDP frame
    00298     if (dma_hdrdesc->hd.frmlen != 0)
    00299     {
    00300         uint16_t framectrl;
    00301         #if NX_AMPDU_TX
    00302         uint32_t statinfo;
    00303         #endif
    00304         struct rx_pbd *pd = HW2CPU(dma_hdrdesc->hd.first_pbd_ptr);
    00305
    00306         // If monitor mode is enabled, we don't handle the frame and it will be uploaded
    00307         // to the upper layers
    00308         if (rx_hwdesc_env.monitor_en)
    00309             return false;
    00310
    00311         // Sanity check: frames with length not NULL have at least 1 buffer descriptor
    00312         ASSERT_REC_VAL(pd != NULL, true);
    00313
    00314         // Get the frame control
    00315         framectrl = co_read16(HW2CPU(pd->datastartptr));
    00316
    00317         #if NX_AMPDU_TX
    00318         // Get the status information from the RX header descriptor
    00319         statinfo = dma_hdrdesc->hd.statinfo;
    00320         #endif
    00321
    00322         // Decode the frame control to know if we have to handle the frame internally
    00323         switch(framectrl & MAC_FCTRL_TYPESUBTYPE_MASK)
    00324         {
    00325             #if NX_AMPDU_TX
    00326             case MAC_FCTRL_BA :
    00327                 // Check if this BA is a response to a sent A-MPDU
    00328                 if ((statinfo & (RX_HD_RSP_FRM | RX_HD_SUCCESS)) ==
    00329                                                        (RX_HD_RSP_FRM | RX_HD_SUCCESS))
    00330                 {
    00331                     //keep BA rxdesc in list to analyse in tx confirm event handler
    00332                     txl_ba_push(rxdesc);
    00333                 }
    00334                 break;
    00335             #endif
    00336             #if NX_MAC_HE
    00337             case MAC_FCTRL_HE_TRIGGER :
    00338                 // Check if this trigger is for us
    00339                 if (statinfo & RX_HD_SUCCESS)
    00340                 {
    00341                     txl_he_trigger_push(rxdesc);
    00342                 }
    00343                 break;
    00344             #endif
    00345             default:
    00346                 // LMAC does not handle this control frame, so forward it to upper MAC
    00347                 handled = false;
    00348                 break;
    00349         }
    00350     }
    00351     else
    00352     {
    00353         // Sanity check: NDP frames have no buffer descriptor attached
    00354         ASSERT_REC_VAL(dma_hdrdesc->hd.first_pbd_ptr == 0, true);
    00355     }
    00356
    00357     // Check if the frame was handled
    00358     if (handled)
    00359     {
    00360         // Control and NDP frames have only one or less RBD
    00361         if (rxdesc->dma_hdrdesc->hd.first_pbd_ptr != 0)
    00362         {
    00363             rxdesc->spare_pbd = HW2CPU(rxdesc->dma_hdrdesc->hd.first_pbd_ptr);
    00364
    00365             // Store the pointer to the next available RBD (for debug and error logs only)
    00366             rx_hwdesc_env.first = HW2CPU(rxdesc->spare_pbd->next);
    00367         }
    00368         else
    00369         {
    00370             rxdesc->spare_pbd = NULL;
    00371         }
    00372         rxdesc->last_pbd = NULL;
    00373
    00374         // Release the frame
    00375         if (rxdesc->spare_pbd != NULL)
    00376         {
    00377             // release the payload descriptors associated with this SW descriptor
    00378             rxl_pd_append(NULL, NULL, rxdesc->spare_pbd);
    00379         }
    00380
    00381         // release the HW DMA descriptors
    00382         rxl_hd_append(rxdesc->dma_hdrdesc);
    00383     }
    00384     return (handled);
    00385 }
    00386
    00412 static struct rx_payloaddesc *rxl_payload_transfer(struct rx_payloaddesc **curr_pd,
    00413                                                    uint16_t upload_len, uint32_t hostbuf,
    00414                                                    uint16_t *payl_offset, int dma_idx,
    00415                                                    int irq_en)
    00416 {
    00417     uint16_t dma_len;
    00418     struct dma_desc *dma_desc;
    00419     struct dma_desc *first_dma_desc;
    00420     struct rx_payloaddesc *pd = *curr_pd;
    00421     struct rx_payloaddesc *prev_pd = NULL;
    00422     uint16_t payl_off = *payl_offset;
    00423
    00424     // Get the IPC DMA descriptor of the MAC header
    00425     dma_desc = &pd->dma_desc[dma_idx];
    00426     // Save the pointer to the first desc, as it will be passed to the DMA driver later
    00427     first_dma_desc = dma_desc;
    00428
    00429     // Loop as long as the MPDU still has data to copy
    00430     while (1)
    00431     {
    00432         struct dma_desc *dma_desc_next;
    00433
    00434         // Fill the destination address of the DMA descriptor
    00435         dma_desc->dest = hostbuf;
    00436         dma_desc->src = pd->pbd.datastartptr + payl_off;
    00437
    00438         // Check if we have reached the last payload buffer containing the MPDU
    00439         if ((upload_len + payl_off) < NX_RX_PAYLOAD_LEN)
    00440         {
    00441             // DMA only the remaining bytes of the payload
    00442             dma_len = upload_len;
    00443
    00444             #if NX_AMSDU_DEAGG
    00445             // Update the offset
    00446             payl_off += upload_len;
    00447             #endif
    00448         }
    00449         else
    00450         {
    00451             // The complete payload buffer has to be DMA'ed
    00452             dma_len = NX_RX_PAYLOAD_LEN - payl_off;
    00453
    00454             // Reset the offset
    00455             payl_off = 0;
    00456         }
    00457
    00458         // Fill the DMA length in the IPC DMA descriptor
    00459         dma_desc->length = dma_len;
    00460
    00461         // By default no DMA IRQ on this intermediate transfer
    00462         dma_desc->ctrl = RX_LLICTRL(0);
    00463
    00464         // Move the pointer in the host buffer
    00465         hostbuf += dma_len;
    00466
    00467         // Compute remaining length to be DMA'ed to host
    00468         upload_len -= dma_len;
    00469
    00470         // Check if we have finished to program the current payload transfer
    00471         if (upload_len == 0)
    00472         {
    00473             break;
    00474         }
    00475
    00476         // Move to the next RBD
    00477         prev_pd = pd;
    00478         pd = (struct rx_payloaddesc *)HW2CPU(pd->pbd.next);
    00479         dma_desc_next = &pd->dma_desc[0];
    00480
    00481         // Sanity check - There shall be a payload descriptor available
    00482         ASSERT_ERR(pd != NULL);
    00483
    00484         // Link the new descriptor with the previous one
    00485         dma_desc->next = CPU2HW(dma_desc_next);
    00486
    00487         // Retrieve the new DMA descriptor from the payload descriptor
    00488         dma_desc = dma_desc_next;
    00489     }
    00490
    00491     // Last descriptor of the MPDU, enable the interrupt on it if requested
    00492     dma_desc->ctrl = RX_LLICTRL(irq_en);
    00493
    00494     // Push the DMA descriptor in the DMA engine
    00495     dma_push(first_dma_desc, dma_desc, RX_DATA_UPLOAD_CHAN);
    00496
    00497     *curr_pd = pd;
    00498     *payl_offset = payl_off;
    00499
    00500     return prev_pd;
    00501 }
    00502
    00503 #if NX_AMSDU_DEAGG
    00504
    00523 static struct rx_payloaddesc *rxl_amsdu_deagg(struct rx_dmadesc *dma_hdrdesc,
    00524                                               struct rx_payloaddesc **curr_pd,
    00525                                               uint16_t mpdu_len, uint32_t hostbuf,
    00526                                               uint16_t payl_offset)
    00527 {
    00528     int dma_idx = 0;
    00529     int msdu_idx = 0;
    00530     uint16_t upload_len;
    00531     struct rx_payloaddesc *pd = *curr_pd;
    00532     struct rx_payloaddesc *prev_pd = NULL;
    00533
    00534     // Reset the A-MSDU hostids
    00535     memset(dma_hdrdesc->amsdu_hostids, 0, sizeof(dma_hdrdesc->amsdu_hostids));
    00536
    00537     // If the MPDU is a A-MSDU, we will upload the different A-MSDU subframes in
    00538     // separate host buffers, so get the length of the first sub-frame
    00539     upload_len = rxl_amsdu_subframe_len_get(pd, payl_offset, mpdu_len);
    00540     // Loop as long as the MPDU still has data to copy
    00541     while (1)
    00542     {
    00543         prev_pd = rxl_payload_transfer(&pd, upload_len, hostbuf, &payl_offset, dma_idx, 0);
    00544         mpdu_len -= upload_len;
    00545
    00546         // Check if we still have A-MSDU subframes to upload and one available buffer
    00547         if ((mpdu_len != 0) && macif_rx_buf_check())
    00548         {
    00549             // Check if the next A-MSDU subframe starts in the same payload descriptor
    00550             // or in the next one
    00551             if (payl_offset)
    00552             {
    00553                 // Move to next DMA descriptor inside the current payload descriptor
    00554                 dma_idx++;
    00555                 // Is there a DMA structure available?
    00556                 if (dma_idx >= NX_DMADESC_PER_RX_PDB_CNT)
    00557                      break;
    00558             }
    00559             else
    00560             {
    00561                 // Move to the next payload descriptor
    00562                 prev_pd = pd;
    00563                 pd = (struct rx_payloaddesc *)HW2CPU(pd->pbd.next);
    00564
    00565                 // Sanity check - There shall be a payload descriptor available
    00566                 ASSERT_ERR(pd != NULL);
    00567
    00568                 dma_idx = 0;
    00569             }
    00570             // Retrieve the length of the next A-MSDU sub-frame
    00571             upload_len = rxl_amsdu_subframe_len_get(pd, payl_offset, mpdu_len);
    00572
    00573             // Check if the next A-MSDU subframe is valid
    00574             if (upload_len == 0)
    00575                 break;
    00576
    00577             // Get a RX buffer
    00578             hostbuf = macif_rx_buf_get(&dma_hdrdesc->amsdu_hostids[msdu_idx++]) +
    00579                       RXL_PAYLOAD_OFFSET;
    00580         }
    00581         else
    00582             break;
    00583     }
    00584
    00585     *curr_pd = pd;
    00586
    00587     return prev_pd;
    00588 }
    00589 #endif // NX_AMSDU_DEAGG
    00590
    00603 static void rxl_go_to_last_rbd(struct rxdesc *rxdesc, struct rx_payloaddesc *pd,
    00604                              struct rx_payloaddesc *prev_pd)
    00605 {
    00606     // Go through the RBD
    00607     while (1)
    00608     {
    00609         uint32_t statinfo = pd->pbd.bufstatinfo;
    00610
    00611         // If this is the last RBD, exit the loop
    00612         if (statinfo & RX_PD_LASTBUF)
    00613             break;
    00614
    00615         // Otherwise move to the next one
    00616         prev_pd = pd;
    00617         pd = (struct rx_payloaddesc *)HW2CPU(pd->pbd.next);
    00618
    00619         // Sanity check - There shall be a payload descriptor available
    00620         ASSERT_REC(pd != NULL);
    00621     };
    00622
    00623     // Store the pointer to the last RBD consumed by the HW. It will be used when freeing the frame
    00624     rxdesc->last_pbd = &prev_pd->pbd;
    00625     rxdesc->spare_pbd = &pd->pbd;
    00626
    00627     // Store the pointer to the next available RBD (for debug and error logs only)
    00628     rx_hwdesc_env.first = HW2CPU(rxdesc->spare_pbd->next);
    00629 }
    00630
    00631 void rxl_hwdesc_init(void)
    00632 {
    00633     uint32_t i;
    00634
    00635     // Reset the environment
    00636     memset(&rx_hwdesc_env, 0, sizeof(rx_hwdesc_env));
    00637
    00638     // Initialize the DMA header descriptor
    00639     for (i = 0; i < NX_RXDESC_CNT; i++)
    00640     {
    00641         // No data buffer directly attached to the RHD
    00642         rx_dma_hdrdesc[i].hd.datastartptr = 0;
    00643         rx_dma_hdrdesc[i].hd.dataendptr = 0;
    00644
    00645         // Fill in the Upattern
    00646         rx_dma_hdrdesc[i].hd.upatternrx = RX_HEADER_DESC_PATTERN;
    00647
    00648         // clear the MPDU status info
    00649         rx_dma_hdrdesc[i].hd.statinfo = 0;
    00650
    00651         // clear the control field
    00652         rx_dma_hdrdesc[i].hd.headerctrlinfo = 0;
    00653
    00654         // Chain to the next RHD
    00655         rx_dma_hdrdesc[i].hd.next = CPU2HW(&rx_dma_hdrdesc[i + 1].hd);
    00656
    00657         // reset the first payload descriptor pointer
    00658         rx_dma_hdrdesc[i].hd.first_pbd_ptr = 0;
    00659
    00660         // Link the HW descriptor with the corresponding SW one
    00661         rx_dma_hdrdesc[i].hd.rxdesc = &rx_swdesc_tab[i];
    00662
    00663         // clear the frame length
    00664         rx_dma_hdrdesc[i].hd.frmlen = 0;
    00665
    00666         // Prepare DMA descriptor for the RX vectors DMA transfer
    00667         rx_dma_hdrdesc[i].dma_desc.src = CPU2HW(&rx_dma_hdrdesc[i].hd.frmlen);
    00668         rx_dma_hdrdesc[i].dma_desc.length = RXL_HEADER_INFO_LEN;
    00669
    00670         // Link the HW descriptor with the corresponding SW one
    00671         rx_swdesc_tab[i].dma_hdrdesc = &rx_dma_hdrdesc[i];
    00672         rx_swdesc_tab[i].upload_cntrl.rxdesc = &rx_swdesc_tab[i];
    00673     }
    00674
    00675     // Reset the next pointer of the last RHD
    00676     rx_dma_hdrdesc[NX_RXDESC_CNT - 1].hd.next = 0;
    00677
    00678     // write the buffer descriptor into the receive header head pointer register
    00679     nxmac_rx_header_head_ptr_set(CPU2HW(&rx_dma_hdrdesc[1].hd));
    00680
    00681     // set new head bit in DMA control register
    00682     nxmac_dma_cntrl_set(NXMAC_RX_HEADER_NEW_HEAD_BIT);
    00683
    00684     // Initialize the buffer descriptors
    00685     // sanity check
    00686     ASSERT_ERR((CPU2HW(&rx_payload_desc[0].buffer) & WORD_ALIGN) == 0);
    00687
    00688     for (i = 0 ; i < NX_RX_PAYLOAD_DESC_CNT ; i++)
    00689     {
    00690         struct rx_payloaddesc *desc = &rx_payload_desc[i];
    00691         struct rx_pbd *pbd = &desc->pbd;
    00692
    00693         pbd->next = CPU2HW(&rx_payload_desc[i+1].pbd);
    00694
    00695         // Update the upattern
    00696         pbd->upattern = RX_PAYLOAD_DESC_PATTERN;
    00697
    00698         // Clear the bufstatinfo
    00699         pbd->bufstatinfo = 0;
    00700
    00701         //   (end pointer is inclusive, hence the -1)
    00702         pbd->datastartptr = CPU2HW(&(desc->buffer[0]));
    00703         pbd->dataendptr   = pbd->datastartptr + NX_RX_PAYLOAD_LEN - 1;
    00704     }
    00705
    00706     // Reset the next pointer on the last one
    00707     rx_payload_desc[NX_RX_PAYLOAD_DESC_CNT - 1].pbd.next = 0;
    00708
    00709     // program new buffer desc header in list for the MAC HW
    00710     nxmac_rx_payload_head_ptr_set(CPU2HW(&rx_payload_desc[1].pbd));
    00711
    00712     // set the new head bit in the DMA control register
    00713     nxmac_dma_cntrl_set(NXMAC_RX_PAYLOAD_NEW_HEAD_BIT);
    00714
    00715     // initialize the RX trigger timers (RPD count reached for trig 1/4 of available , packet timeout is 1*32us, absolute is 10*32us)
    00716     nxmac_rx_trigger_timer_pack(NX_RX_PAYLOAD_DESC_CNT/4, 1, 10);
    00717
    00718     // initialize the first element of the DMA header pool
    00719     rx_hwdesc_env.free_dmadesc = &rx_dma_hdrdesc[0];
    00720     rx_hwdesc_env.first_dmadesc = &rx_dma_hdrdesc[1];
    00721     rx_hwdesc_env.last_dmadesc = &rx_dma_hdrdesc[NX_RXDESC_CNT - 1];
    00722
    00723     // Record the last buffer desc
    00724     rx_hwdesc_env.free = &rx_payload_desc[0].pbd;
    00725     rx_hwdesc_env.first = &rx_payload_desc[1].pbd;
    00726     rx_hwdesc_env.last = &rx_payload_desc[NX_RX_PAYLOAD_DESC_CNT - 1].pbd;
    00727
    00728     co_list_init(&rx_hwdesc_env.ready);
    00729 }
    00730
    00731 void rxl_hwdesc_monitor(bool enable)
    00732 {
    00733     // Set the monitor flag, so that BA and other control frames are forwarded to the
    00734     // upper layers or handled internally
    00735     rx_hwdesc_env.monitor_en = enable;
    00736 }
    00737
    00738 void rxl_frame_release(struct rxdesc* rxdesc)
    00739 {
    00740     // HW descriptor release needs to be protected
    00741     GLOBAL_INT_DISABLE();
    00742
    00743     // release the payload descriptors associated with this SW descriptor
    00744     rxl_pd_append(HW2CPU(rxdesc->dma_hdrdesc->hd.first_pbd_ptr), rxdesc->last_pbd, rxdesc->spare_pbd);
    00745
    00746     // release the HW DMA descriptors
    00747     rxl_hd_append(rxdesc->dma_hdrdesc);
    00748
    00749     // Re-enable the interrupts
    00750     GLOBAL_INT_RESTORE();
    00751 }
    00752
    00753 void rxl_mpdu_copy(struct rx_pbd *pbd, uint16_t length, uint16_t offset, uint32_t *dst)
    00754 {
    00755     uint16_t dst_offset = 0;
    00756     uint32_t *src;
    00757     while (length)
    00758     {
    00759         uint16_t copy_len;
    00760         if (length < (NX_RX_PAYLOAD_LEN - offset))
    00761             copy_len = length;
    00762         else
    00763             copy_len = NX_RX_PAYLOAD_LEN - offset;
    00764
    00765         src = HW2CPU(pbd->datastartptr + offset);
    00766         co_copy32(dst + dst_offset/4, src, copy_len);
    00767
    00768         length -= copy_len;
    00769         offset = 0;
    00770         dst_offset += copy_len;
    00771         pbd = HW2CPU(pbd->next);
    00772         ASSERT_ERR(pbd != NULL);
    00773     }
    00774 }
    00775
    00776 void rxl_mpdu_partial_transfer(struct rxdesc *rxdesc, uint16_t upload_len,
    00777                                uint32_t hostbuf, uint16_t payl_offset,
    00778                                cb_rx_dma_func_ptr cb, void *env)
    00779 {
    00780     struct rx_dmadesc *dma_hdrdesc = rxl_dmadesc_get(rxdesc);
    00781     struct rx_payloaddesc *pd = HW2CPU(dma_hdrdesc->hd.first_pbd_ptr);
    00782     struct rx_payloaddesc *prev_pd = NULL;
    00783
    00784     // for profiling
    00785     RX_MPDU_XFER_SET();
    00786
    00787     // Program the payload transfer
    00788     prev_pd = rxl_payload_transfer(&pd, upload_len, hostbuf, &payl_offset, 0, 1);
    00789
    00790     // Now go through the additional RBD if any (e.g. for FCS, ICV)
    00791     rxl_go_to_last_rbd(rxdesc, pd, prev_pd);
    00792
    00793     // for profiling
    00794     RX_MPDU_XFER_CLR();
    00795
    00796     // Update upload control descriptor
    00797     rxdesc->upload_cntrl.cb = cb;
    00798     rxdesc->upload_cntrl.env = env;
    00799
    00800     // Insert the element in the pending list
    00801     rxl_upload_cntrl_push_pending(&rxdesc->upload_cntrl);
    00802 }
    00803
    00804 void rxl_mpdu_transfer(struct rxdesc *rxdesc)
    00805 {
    00806     #if (NX_UMAC_PRESENT)
    00807     struct rx_cntrl_rx_status *rx_status = &rxu_cntrl_env.rx_status;
    00808     uint16_t payl_offset = rx_status->payl_offset;
    00809     #else
    00810     uint16_t payl_offset = 0;
    00811     #endif
    00812     uint32_t hostbuf, hostbuf_start;
    00813     struct dma_desc *dma_desc;
    00814     struct rx_dmadesc *dma_hdrdesc = rxl_dmadesc_get(rxdesc);
    00815     uint16_t mpdu_len;
    00816     struct rx_payloaddesc *pd;
    00817     struct rx_payloaddesc *prev_pd = NULL;
    00818
    00819     // for profiling
    00820     RX_MPDU_XFER_SET();
    00821
    00822     // Cache the pointers for faster access
    00823     pd = (struct rx_payloaddesc *)HW2CPU(dma_hdrdesc->hd.first_pbd_ptr);
    00824
    00825     // Get a host buffer address for DMA transfer (host buffer) if needed
    00826     #if (NX_UMAC_PRESENT)
    00827     hostbuf_start = macif_rx_buf_get(&rxu_cntrl_env.hostid_current);
    00828     #else
    00829     hostbuf_start = macif_rx_buf_get();
    00830     #endif //(NX_UMAC_PRESENT)
    00831
    00832     // Copy at the beginning of the host buffer + offset
    00833     hostbuf = hostbuf_start + RXL_PAYLOAD_OFFSET;
    00834
    00835     // Get the MPDU body length
    00836     mpdu_len = dma_hdrdesc->hd.frmlen;
    00837
    00838     // Sanity check - The frame length cannot be NULL...
    00839     ASSERT_REC(mpdu_len != 0);
    00840     // as well as not greater than the max allowed length
    00841     ASSERT_REC(mpdu_len <= RWNX_MAX_AMSDU_RX);
    00842
    00843     #if NX_AMSDU_DEAGG
    00844     // Check if the frame is a A-MSDU
    00845     if (dma_hdrdesc->flags & RX_FLAGS_IS_AMSDU_BIT)
    00846     {
    00847         // If the MPDU is a A-MSDU and the A-MSDU deaggregator is compiled, call the
    00848         // A-MSDU de-aggregation function
    00849         prev_pd = rxl_amsdu_deagg(dma_hdrdesc, &pd, mpdu_len, hostbuf, payl_offset);
    00850     }
    00851     else
    00852     #endif
    00853     {
    00854         // If the MPDU is not a A-MSDU, or if the A-MSDU deaggregator is not compiled,
    00855         // then we will upload the complete packet in a single host buffer
    00856         prev_pd = rxl_payload_transfer(&pd, mpdu_len, hostbuf, &payl_offset, 0, 0);
    00857
    00858         #if (NX_UMAC_PRESENT)
    00859         // Save position of next fragment upload
    00860         rx_status->host_buf_addr = hostbuf + mpdu_len;
    00861         #endif
    00862     }
    00863
    00864     // Get the information on the current channel from the PHY driver
    00865     phy_get_channel(&dma_hdrdesc->phy_info, PHY_PRIM);
    00866     // Now elaborate the final DMA sending for the PHY Vectors and status
    00867     // "Stamp" it as the final DMA of this MPDU transfer: insert a pattern for the upper
    00868     // layer to be able to know that this hostbuf has been filled
    00869     dma_hdrdesc->pattern = DMA_HD_RXPATTERN;
    00870     // Get the IPC DMA descriptor of the PHYVECT header part
    00871     dma_desc = &dma_hdrdesc->dma_desc;
    00872     // Link the new DMA desc with the previous one
    00873     dma_desc->next = CPU2HW(&dma_hdrdesc->dma_desc);
    00874     // Fill the destination address of the DMA descriptor
    00875     // (hostbuf address is already up-to-date at this point)
    00876     dma_desc->dest = hostbuf_start;
    00877
    00878     #if NX_UMAC_PRESENT && !NX_FULLY_HOSTED
    00879     // Interruption only needed for the descriptor
    00880     dma_desc->ctrl = RX_LLICTRL(0);
    00881     #else
    00882     // Last descriptor of the MPDU, so enable the interrupt on it
    00883     dma_desc->ctrl = RX_LLICTRL(1);
    00884     #endif //NX_UMAC_PRESENT && !NX_FULLY_HOSTED
    00885
    00886     // Push the DMA descriptor in the DMA engine
    00887     dma_push(dma_desc, dma_desc, RX_DATA_UPLOAD_CHAN);
    00888
    00889     // Now go through the additional RBD if any (e.g. for FCS, ICV)
    00890     rxl_go_to_last_rbd(rxdesc, pd, prev_pd);
    00891
    00892     // for profiling
    00893     RX_MPDU_XFER_CLR();
    00894
    00895     #if NX_FULLY_HOSTED || !NX_UMAC_PRESENT
    00896     // and push it in the pending list
    00897     rxl_upload_cntrl_push_pending(&rxdesc->upload_cntrl);
    00898     #endif
    00899 }
    00900
    00901 void rxl_mpdu_free(struct rxdesc *rxdesc)
    00902 {
    00903     struct rx_payloaddesc *pd;
    00904     struct rx_payloaddesc *prev_pd = NULL;
    00905     struct rx_dmadesc *dma_hdrdesc = rxl_dmadesc_get(rxdesc);
    00906
    00907     RX_MPDU_FREE_SET();
    00908
    00909     // Cache the pointers for faster access
    00910     pd = (struct rx_payloaddesc *)HW2CPU(dma_hdrdesc->hd.first_pbd_ptr);
    00911
    00912     // Go through the RBD
    00913     rxl_go_to_last_rbd(rxdesc, pd, prev_pd);
    00914
    00915     // Release the frame
    00916     rxl_frame_release(rxdesc);
    00917
    00918     RX_MPDU_FREE_CLR();
    00919 }
    00920
    00921 struct rxdesc *rxl_rxdesc_get(void)
    00922 {
    00923     // Pick a SW descriptor from the list
    00924     return ((struct rxdesc *)co_list_pick(&rx_hwdesc_env.ready));
    00925 }
    00926
    00927 void rxl_rxdesc_ready_for_processing(struct rxdesc *rxdesc)
    00928 {
    00929     // Nothing special to do on the descriptor, except popping it from the ready list
    00930     GLOBAL_INT_DISABLE();
    00931     co_list_pop_front(&rx_hwdesc_env.ready);
    00932     GLOBAL_INT_RESTORE();
    00933 }
    00934
    00935 void rxl_mpdu_isr(void)
    00936 {
    00937     struct rx_dmadesc *dma_hdrdesc;
    00938     struct rxdesc *rxdesc;
    00939
    00940     // for profiling
    00941     PROF_RX_MAC_IRQ_SET();
    00942
    00943     // clear the interrupt
    00944     nxmac_tx_rx_int_ack_clear(NXMAC_TIMER_RX_TRIGGER_BIT | NXMAC_COUNTER_RX_TRIGGER_BIT);
    00945
    00946     while (1)
    00947     {
    00948         // check if there are more elements to handle
    00949         if ((rx_hwdesc_env.first_dmadesc == NULL) ||
    00950             (!RX_HD_DONE_GET(rx_hwdesc_env.first_dmadesc->hd.statinfo)))
    00951             break;
    00952
    00953         // retrieve the pointer to the first element of the list
    00954         dma_hdrdesc = rx_hwdesc_env.first_dmadesc;
    00955
    00956         // prepare the SW descriptor for this frame
    00957         rxdesc = dma_hdrdesc->hd.rxdesc;
    00958
    00959         // get the next Header descriptor pointer now as it may be modified by
    00960         // rxl_rxcntrl_frame() if the frame is released immediately
    00961         rx_hwdesc_env.first_dmadesc = (struct rx_dmadesc*)HW2CPU(dma_hdrdesc->hd.next);
    00962
    00963         // check if it is a control frame and handle it if necessary
    00964         if (!rxl_rxcntrl_frame(rxdesc))
    00965         {
    00966             // Reset upload control structure
    00967             #if NX_FULLY_HOSTED
    00968             rxdesc->upload_cntrl.cb = NULL;
    00969             #else
    00970             rxdesc->upload_cntrl.cb = rxl_host_irq_mitigation_update;
    00971             #endif
    00972             rxdesc->upload_cntrl.env = NULL;
    00973             // Push the frame to the ready list
    00974             co_list_push_back(&rx_hwdesc_env.ready, &rxdesc->upload_cntrl.list_hdr);
    00975         }
    00976     }
    00977
    00978     // Check if frames are ready
    00979     if (!co_list_is_empty(&rx_hwdesc_env.ready))
    00980     {
    00981         if (macif_rx_buf_check())
    00982         {
    00983             ke_evt_set(KE_EVT_RXREADY_BIT);
    00984         }
    00985     }
    00986
    00987     // for profiling
    00988     PROF_RX_MAC_IRQ_CLR();
    00989 }
    00990
    00991 void rxl_immediate_frame_get(void)
    00992 {
    00993     rxl_mpdu_isr();
    00994 }
    00995
    00996 void rxl_current_desc_get(struct rx_hd **rhd, struct rx_pbd **rbd)
    00997 {
    00998     // First RX Header Descriptor chained to the HW
    00999     *rhd = &(rx_hwdesc_env.free_dmadesc->hd);
    01000
    01001     // First RX Buffer Descriptor chained to the HW
    01002     *rbd = rx_hwdesc_env.free;
    01003 }
    01004