- Main Page
- Modules
- Data Structures
- Files

- File List
- Globals

# /space/home/slher/rel/Beken/v6_4_5/macsw/plf/refip/src/driver/ipc/ipc_emb.c

Go to the documentation of this file.

    00001
    00019 /*
    00020  * INCLUDE FILES
    00021  ****************************************************************************************
    00022  */
    00023 #include <string.h>
    00024
    00025 #include "rwnx_config.h"
    00026 #include "dbg_assert.h"
    00027
    00028 #include "co_math.h"
    00029 #include "ke_mem.h"
    00030 #include "ke_msg.h"
    00031 #include "ke_task.h"
    00032 #include "ke_event.h"
    00033
    00034 #include "tx_swdesc.h"
    00035 #include "rxl_cntrl.h"
    00036 #include "txl_buffer.h"
    00037
    00038 #include "dma.h"
    00039 #include "ipc_emb.h"
    00040 #include "ipc_shared.h"
    00041
    00042 #include "sysctrl.h"
    00043
    00044 #include "dbg.h"
    00045
    00046 #include "txl_cntrl.h"
    00047 #if NX_AMPDU_TX
    00048 #include "txl_agg.h"
    00049 #endif
    00050
    00051 #if (NX_UMAC_PRESENT)
    00052 #include "txu_cntrl.h"
    00053 #endif //(NX_UMAC_PRESENT)
    00054
    00055 /*
    00056  * DEFINES AND MACROS
    00057  ****************************************************************************************
    00058  */
    00060 #define MSG_LLICTRL(irqenable)                                                           \
    00061     ( (irqenable)?(IPC_DMA_LLI_IRQ_EN|(IPC_DMA_LLI_MSG << IPC_DMA_LLI_IRQ_POS)) : 0)
    00062
    00064 #define DBG_LLICTRL(irqenable)                                                           \
    00065     ( (irqenable)?(IPC_DMA_LLI_IRQ_EN|(IPC_DMA_LLI_DBG << IPC_DMA_LLI_IRQ_POS)) : 0)
    00066
    00068 #if NX_BEACONING
    00069 #define ALL_EVENTS_TX  (KE_EVT_MACIF_TXDESC_AC0_BIT | KE_EVT_MACIF_TXDESC_AC1_BIT |  \
    00070                         KE_EVT_MACIF_TXDESC_AC2_BIT | KE_EVT_MACIF_TXDESC_AC3_BIT |  \
    00071                         KE_EVT_MACIF_TXDESC_BCN_BIT)
    00072 #else
    00073 #define ALL_EVENTS_TX  (KE_EVT_MACIF_TXDESC_AC0_BIT | KE_EVT_MACIF_TXDESC_AC1_BIT |  \
    00074                         KE_EVT_MACIF_TXDESC_AC2_BIT | KE_EVT_MACIF_TXDESC_AC3_BIT)
    00075 #endif
    00076
    00078 #if NX_UMAC_PRESENT && NX_BEACONING
    00079 #define HIGH_PRIO_EVT (KE_EVT_RXREADY_BIT | KE_EVT_PRIMARY_TBTT_BIT | KE_EVT_MACIF_TXDESC_BCN_BIT)
    00080 #else
    00081 #define HIGH_PRIO_EVT (KE_EVT_RXREADY_BIT | KE_EVT_PRIMARY_TBTT_BIT)
    00082 #endif
    00083
    00084 /*
    00085  * VARIABLES
    00086  ****************************************************************************************
    00087  */
    00089 const uint32_t ipc_emb_evt_bit[NX_TXQ_CNT] =
    00090 {
    00091     #if NX_BEACONING
    00092     [AC_BCN] = KE_EVT_MACIF_TXDESC_BCN_BIT,
    00093     #endif
    00094     [AC_VO] = KE_EVT_MACIF_TXDESC_AC3_BIT,
    00095     [AC_VI] = KE_EVT_MACIF_TXDESC_AC2_BIT,
    00096     [AC_BE] = KE_EVT_MACIF_TXDESC_AC1_BIT,
    00097     [AC_BK] = KE_EVT_MACIF_TXDESC_AC0_BIT,
    00098 };
    00099
    00101 struct ipc_emb_env_tag ipc_emb_env;
    00102
    00104 const int nx_txdesc_cnt_msk[] =
    00105 {
    00106     NX_TXDESC_CNT0 - 1,
    00107     NX_TXDESC_CNT1 - 1,
    00108     NX_TXDESC_CNT2 - 1,
    00109     NX_TXDESC_CNT3 - 1,
    00110     #if (NX_BEACONING)
    00111     NX_TXDESC_CNT4 - 1,
    00112     #endif
    00113 };
    00114
    00115 /*
    00116  * FUNCTIONS DEFINITIONS
    00117  ****************************************************************************************
    00118  */
    00128 __INLINE void ipc_emb_txdesc_copy(struct txdesc *dst_local, volatile struct txdesc_host *src_shared)
    00129 {
    00130     // Copy the host descriptor at the right place in the EMB descriptor
    00131     volatile uint32_t *src = (uint32_t*) &src_shared->api;
    00132     uint32_t *dst = (uint32_t*) &dst_local->host;
    00133
    00134     // we are copying bytes 4 by 4. Hope that the additional bytes
    00135     // in the dest will not suffer the overwrite.
    00136     for (unsigned int i = 0; i < (sizeof_b(struct txdesc_api)+3)/4; i++)
    00137     {
    00138         dst[i] = src[i];
    00139     }
    00140 }
    00141
    00142 uint8_t ipc_emb_tx_q_len(int queue_idx, int vif_idx)
    00143 {
    00144     volatile struct txdesc_host *ptr, *start, *end;
    00145     uint8_t i = 0, index, nb = 0;
    00146
    00147     #if 1 //RW_MUMIMO_TX_EN
    00148     for (i = 0; i < nx_txuser_cnt[queue_idx]; i++)
    00149     {
    00150     #endif
    00151         index = ipc_emb_env.txdesc_idx[queue_idx][i] & nx_txdesc_cnt_msk[queue_idx];
    00152         ptr = &ipc_emb_env.txdesc[queue_idx][i][index];
    00153         end = &ipc_emb_env.txdesc[queue_idx][i][nx_txdesc_cnt_msk[queue_idx]];
    00154         if (index == 0)
    00155             start = NULL;
    00156         else
    00157             start = &ipc_emb_env.txdesc[queue_idx][i][0];
    00158
    00159         while (ptr->ready) {
    00160             if (vif_idx == ptr->api.host.vif_idx)
    00161                 nb++;
    00162             if (ptr == end) {
    00163                 if (start)
    00164                 {
    00165                     ptr = start;
    00166                     end = &ipc_emb_env.txdesc[queue_idx][i][index - 1];
    00167                     start = NULL;
    00168                 }
    00169                 else
    00170                     break;
    00171             }
    00172             else
    00173                 ptr++;
    00174         }
    00175     #if 1 // RW_MUMIMO_TX_EN
    00176     }
    00177     #endif
    00178
    00179     return nb;
    00180 }
    00181
    00185 void ipc_emb_init(void)
    00186 {
    00187     int i;
    00188
    00189     // clear the entire IPC EMB environment
    00190     memset(&ipc_emb_env, 0, sizeof(ipc_emb_env));
    00191
    00192     // Set the TX descriptor array pointers
    00193     for (i = 0; i < RW_USER_MAX; i++)
    00194     {
    00195         ipc_emb_env.txdesc[0][i] = ipc_shared_env.txdesc0[i];
    00196         ipc_emb_env.txdesc[1][i] = ipc_shared_env.txdesc1[i];
    00197         ipc_emb_env.txdesc[2][i] = ipc_shared_env.txdesc2[i];
    00198         ipc_emb_env.txdesc[3][i] = ipc_shared_env.txdesc3[i];
    00199         #if (NX_BEACONING)
    00200         ipc_emb_env.txdesc[4][i] = NULL;
    00201         #endif
    00202     }
    00203     #if (NX_BEACONING)
    00204     ipc_emb_env.txdesc[4][0] = ipc_shared_env.txdesc4[0];
    00205     #endif
    00206
    00207     #if RW_MUMIMO_TX_EN
    00208     for (i=0; i < IPC_TXQUEUE_CNT; i++)
    00209     {
    00210         ipc_emb_env.user_active[i] = (1 << nx_txuser_cnt[i]) - 1;
    00211     }
    00212     #endif
    00213
    00214     //Set compatibility info
    00215     #ifdef CFG_IPC_VER_10
    00216     ipc_shared_env.comp_info.ipc_shared_version = 10;
    00217     #else
    00218     ipc_shared_env.comp_info.ipc_shared_version = 11;
    00219     #endif /* CFG_IPC_VER_V10 */
    00220     ipc_shared_env.comp_info.msg_api= MSG_API_VER;
    00221     ipc_shared_env.comp_info.msge2a_buf_cnt = IPC_MSGE2A_BUF_CNT;
    00222     ipc_shared_env.comp_info.dbgbuf_cnt = IPC_DBGBUF_CNT;
    00223     ipc_shared_env.comp_info.radarbuf_cnt = IPC_RADARBUF_CNT;
    00224     ipc_shared_env.comp_info.unsuprxvecbuf_cnt = IPC_UNSUPRXVECBUF_CNT;
    00225     ipc_shared_env.comp_info.rxbuf_cnt = IPC_RXBUF_CNT;
    00226     #if NX_UMAC_PRESENT
    00227     ipc_shared_env.comp_info.rxdesc_cnt= IPC_RXDESC_CNT;
    00228     #endif //(NX_UMAC_PRESENT)
    00229     ipc_shared_env.comp_info.bk_txq = NX_TXDESC_CNT0;
    00230     ipc_shared_env.comp_info.be_txq = NX_TXDESC_CNT1;
    00231     ipc_shared_env.comp_info.vi_txq = NX_TXDESC_CNT2;
    00232     ipc_shared_env.comp_info.vo_txq = NX_TXDESC_CNT3;
    00233     #if NX_BEACONING
    00234         ipc_shared_env.comp_info.bcn_txq = NX_TXDESC_CNT4;
    00235     #else
    00236         ipc_shared_env.comp_info.bcn_txq = 0;
    00237     #endif /* NX_BEACONING */
    00238     ipc_shared_env.comp_info.ipc_shared_size = sizeof_b(ipc_shared_env);
    00239
    00240     // Set unchanged fields of the MSG DMA descriptor (to send MSGs to App)
    00241     //   - DMA contents always starts at
    00242     ipc_shared_env.msg_dma_desc.src = CPU2HW(&(ipc_shared_env.msg_e2a_buf));
    00243     //   - length
    00244     ipc_shared_env.msg_dma_desc.length = sizeof_b(struct ipc_e2a_msg);
    00245     //   - no other descriptor will be linked to it
    00246     ipc_shared_env.msg_dma_desc.next = 0;
    00247     //   - enable interrupt generation on this descriptor
    00248     ipc_shared_env.msg_dma_desc.ctrl = MSG_LLICTRL(1);
    00249     // Put the pattern in the msg buffer
    00250     ipc_shared_env.msg_e2a_buf.pattern = IPC_MSGE2A_VALID_PATTERN;
    00251
    00253     //   - DMA contents always starts at
    00254     ipc_shared_env.dbg_dma_desc.src = CPU2HW(&(ipc_shared_env.dbg_buf));
    00255     //   - length
    00256     ipc_shared_env.dbg_dma_desc.length = sizeof_b(struct ipc_dbg_msg);
    00257     //   - no other descriptor will be linked to it
    00258     ipc_shared_env.dbg_dma_desc.next = 0;
    00259     //   - enable interrupt generation on this descriptor
    00260     ipc_shared_env.dbg_dma_desc.ctrl = DBG_LLICTRL(1);
    00261     // Put the pattern in the debug buffer
    00262     ipc_shared_env.dbg_buf.pattern = IPC_DBG_VALID_PATTERN;
    00263
    00264     // Sanity check - verify that the FW is compiled with the right IPC version
    00265     ASSERT_ERR(ipc_emb_signature_get() == IPC_EMB_SIGNATURE_RESET);
    00266
    00267     // configure the IPC line selection
    00268     #ifdef CFG_IPC_VER_V10
    00269     ipc_app2emb_line_sel_set(0);
    00270     #else
    00271     ipc_app2emb_line_sel_low_set(0);
    00272     ipc_app2emb_line_sel_high_set(0);
    00273     #endif /* CFG_IPC_VER_V10 */
    00274
    00275     ipc_app2emb0_sel_setf(0); // DBG
    00276     ipc_app2emb1_sel_setf(1); // MSG
    00277     ipc_app2emb4_sel_setf(2); // RXDESC_BACK
    00278     ipc_app2emb5_sel_setf(2); // RXBUF_BACK
    00279     ipc_app2emb6_sel_setf(2); // TXCFM_BACK
    00280
    00281     // TX desc interrupts
    00282     ipc_app2emb8_sel_setf(3);
    00283     ipc_app2emb9_sel_setf(3);
    00284     ipc_app2emb10_sel_setf(3);
    00285     ipc_app2emb11_sel_setf(3);
    00286     ipc_app2emb12_sel_setf(3);
    00287
    00288     #if (RW_USER_MAX > 1)
    00289     ipc_app2emb13_sel_setf(3);
    00290     ipc_app2emb14_sel_setf(3);
    00291     ipc_app2emb15_sel_setf(3);
    00292     ipc_app2emb16_sel_setf(3);
    00293     #endif /* RW_USER_MAX > 1 */
    00294
    00295     #if (RW_USER_MAX > 2)
    00296     ipc_app2emb17_sel_setf(3);
    00297     ipc_app2emb18_sel_setf(3);
    00298     ipc_app2emb19_sel_setf(3);
    00299     ipc_app2emb20_sel_setf(3);
    00300     #endif /* RW_USER_MAX > 2 */
    00301
    00302     #if (RW_USER_MAX > 3)
    00303     ipc_app2emb21_sel_setf(3);
    00304     ipc_app2emb22_sel_setf(3);
    00305     ipc_app2emb23_sel_setf(3);
    00306     ipc_app2emb24_sel_setf(3);
    00307     #endif /* RW_USER_MAX > 3 */
    00308
    00309     // enable the all interrupts from APP
    00310     ipc_app2emb_unmask_set(IPC_IRQ_A2E_ALL);
    00311 }
    00312
    00319 void ipc_emb_tx_flow_off(void)
    00320 {
    00321     // mask Tx IPC irqs
    00322     ipc_app2emb_unmask_clear(IPC_IRQ_A2E_TXDESC);
    00323
    00324     // Clear all IPC Tx events
    00325     ke_evt_clear(ALL_EVENTS_TX);
    00326 }
    00327
    00328 void ipc_emb_tx_flow_on(void)
    00329 {
    00330     // unmask Tx IPC irqs
    00331     ipc_app2emb_unmask_set(IPC_IRQ_A2E_TXDESC);
    00332
    00333     // Set all IPC Tx events
    00334     //ke_evt_set(ALL_EVENTS_TX);
    00335 }
    00336
    00337
    00338 void ipc_emb_tx_irq(void)
    00339 {
    00340     // read HW IPC irq
    00341     uint32_t stat = ipc_app2emb_status_get() & IPC_IRQ_A2E_TXDESC;
    00342
    00343     if (stat)
    00344     {
    00345         // For profiling
    00346         PROF_TX_IPC_IRQ_SET();
    00347
    00348         // set IPC Tx event
    00349         ke_evt_set(ipc_emb_tx_evt_field(stat));
    00350
    00351         // mask Tx IPC irq
    00352         ipc_app2emb_unmask_clear(stat);
    00353
    00354         // clear the pending TX IRQ
    00355         ipc_app2emb_ack_clear(stat);
    00356
    00357         // For profiling
    00358         PROF_TX_IPC_IRQ_CLR();
    00359     }
    00360 }
    00361
    00362
    00366 void ipc_emb_tx_evt(int queue_idx)
    00367 {
    00368     volatile struct txdesc_host *txdesc_src;
    00369     uint32_t evt_bit = ipc_emb_evt_bit[queue_idx];
    00370     bool pushed = false;
    00371     int i = 0;
    00372
    00373     // For profiling
    00374     PROF_TX_MACIF_EVT_SET();
    00375
    00376     // Clear the event that was just triggered
    00377     ke_evt_clear(evt_bit);
    00378
    00379     #if RW_MUMIMO_TX_EN
    00380     // Loop on all users
    00381     for (i = 0; i < nx_txuser_cnt[queue_idx]; i++)
    00382     #endif
    00383     {
    00384         struct txdesc *txdesc_base = txdesc_array[queue_idx][i];
    00385         volatile struct txdesc_host *txdesc_src_base = ipc_emb_env.txdesc[queue_idx][i];
    00386         uint32_t *txdesc_idx = &ipc_emb_env.txdesc_idx[queue_idx][i];
    00387
    00388         #if RW_MUMIMO_TX_EN
    00389         bool stop_user = false;
    00390
    00391         // Check if this user position can be scheduled currently
    00392         if (!(ipc_emb_env.user_active[queue_idx] & CO_BIT(i)))
    00393             continue;
    00394         #endif
    00395
    00396         txdesc_src = &txdesc_src_base[*txdesc_idx & nx_txdesc_cnt_msk[queue_idx]];
    00397
    00398         // Loop on all the ready descriptors
    00399         while (txdesc_src->ready)
    00400         {
    00401             struct txdesc *txdesc_new;
    00402
    00403             // Check if we have higher priority event pending
    00404             #if NX_UMAC_PRESENT && NX_BEACONING
    00405             if (!(evt_bit & KE_EVT_MACIF_TXDESC_BCN_BIT))
    00406             #endif
    00407             {
    00408                 if (ke_evt_get() & HIGH_PRIO_EVT)
    00409                 {
    00410                     // For profiling
    00411                     PROF_TX_MACIF_EVT_CLR();
    00412
    00413                     // Set again the event that was just triggered
    00414                     ke_evt_set(evt_bit);
    00415                     return;
    00416                 }
    00417             }
    00418
    00419             // clear any possible pending TX IRQ (in case the host has pushed new packets)
    00420             ipc_app2emb_ack_clear(CO_BIT(i + RW_USER_MAX * queue_idx + IPC_IRQ_A2E_TXDESC_FIRSTBIT));
    00421
    00422             // allocation of the tx descriptor
    00423             txdesc_new = &txdesc_base[*txdesc_idx & nx_txdesc_cnt_msk[queue_idx]];
    00424
    00425             // copy the descriptor
    00426             ipc_emb_txdesc_copy(txdesc_new, txdesc_src);
    00427
    00428             // Initialize some fields of the descriptor
    00429             txdesc_new->lmac.agg_desc = NULL;
    00430             txdesc_new->lmac.hw_desc->cfm.status = 0;
    00431             #if (RW_BFMER_EN)
    00432             txdesc_new->lmac.bfr_node = NULL;
    00433             #endif //(RW_BFMER_EN)
    00434             #if (NX_UMAC_PRESENT)
    00435             txdesc_new->umac.buf_control = NULL;
    00436             #endif
    00437
    00438             #if RW_MUMIMO_TX_EN
    00439             ASSERT_ERR(i == get_user_pos(txdesc_new));
    00440             stop_user =
    00441             #endif
    00442             #if (NX_UMAC_PRESENT)
    00443             // push the descriptor in the UMAC
    00444             txu_cntrl_push(txdesc_new, queue_idx);
    00445             #else
    00446             // push the descriptor in the LMAC
    00447             txl_cntrl_push(txdesc_new, queue_idx);
    00448             #endif //(NX_UMAC_PRESENT)
    00449
    00450             // Now we have pushed some payloads so we may need to trigger the prepare event
    00451             pushed = true;
    00452
    00453             // the descriptor has been consumed
    00454             txdesc_src->ready = 0;
    00455
    00456             // increment the embedded index by one
    00457             (*txdesc_idx)++;
    00458
    00459             #if RW_MUMIMO_TX_EN
    00460             // Check if we are done with this user
    00461             if (stop_user)
    00462                 break;
    00463             #endif
    00464
    00465             // Go to next descriptor
    00466             txdesc_src = &txdesc_src_base[*txdesc_idx & nx_txdesc_cnt_msk[queue_idx]];
    00467         }
    00468
    00469         #if RW_MUMIMO_TX_EN
    00470         // Proceed to the user stopping and switch if required
    00471         if (stop_user)
    00472         {
    00473             // Make user inactive
    00474             ipc_emb_env.user_active[queue_idx] &= ~CO_BIT(i);
    00475             // Schedule next user
    00476             continue;
    00477         }
    00478         #endif
    00479     }
    00480
    00481     // Check if some payloads have been pushed and have to be downloaded
    00482     if (pushed)
    00483     {
    00484         #if (NX_AMPDU_TX)
    00485         // Check if the current A-MPDU under construction has to be closed
    00486         txl_agg_check(queue_idx);
    00487         #endif //(NX_AMPDU_TX)
    00488     }
    00489
    00490     // re-enable the IPC interrupts for the TX queues
    00491     #if RW_MUMIMO_TX_EN
    00492     ipc_app2emb_unmask_set((ipc_emb_env.user_active[queue_idx] << (RW_USER_MAX * queue_idx + IPC_IRQ_A2E_TXDESC_FIRSTBIT))
    00493                            & IPC_IRQ_A2E_TXDESC);
    00494     #else
    00495     ipc_app2emb_unmask_set(CO_BIT(queue_idx + IPC_IRQ_A2E_TXDESC_FIRSTBIT)
    00496                                                         & IPC_IRQ_A2E_TXDESC);
    00497     #endif
    00498
    00499     // For profiling
    00500     PROF_TX_MACIF_EVT_CLR();
    00501 }
    00502
    00509 void ipc_emb_cfmback_irq(void)
    00510 {
    00511     // read HW IPC irq
    00512     uint32_t stat = ipc_app2emb_status_get();
    00513
    00514     if (stat & IPC_IRQ_A2E_RXBUF_BACK)
    00515     {
    00516         // Mask RX buffer back IPC irq
    00517         ipc_app2emb_unmask_clear(IPC_IRQ_A2E_RXBUF_BACK);
    00518
    00519         // Ack it
    00520         ipc_app2emb_ack_clear(IPC_IRQ_A2E_RXBUF_BACK);
    00521
    00522         // Trigger the RX event handler because we now have some RX buffers
    00523         // available
    00524         ke_evt_set(KE_EVT_RXREADY_BIT);
    00525     }
    00526
    00527     #if NX_UMAC_PRESENT
    00528     if (stat & IPC_IRQ_A2E_RXDESC_BACK)
    00529     {
    00530         // Mask RX buffer back IPC irq
    00531         ipc_app2emb_unmask_clear(IPC_IRQ_A2E_RXDESC_BACK);
    00532
    00533         // Ack it
    00534         ipc_app2emb_ack_clear(IPC_IRQ_A2E_RXDESC_BACK);
    00535
    00536         // Trigger the RX event handler because we now have some RX buffers
    00537         // available
    00538         ke_evt_set(KE_EVT_RXUREADY_BIT);
    00539     }
    00540     #endif
    00541 }
    00542
    00555 static uint32_t ipc_emb_hostmsgbuf_get(void)
    00556 {
    00557     uint32_t hostmsgbuf;
    00558
    00559     do
    00560     {
    00561         // Retrieve the wished hostbuf address
    00562         hostmsgbuf = ipc_shared_env.msg_e2a_hostbuf_addr[ipc_emb_env.ipc_msge2a_buf_idx];
    00563
    00564         // Check if the host buffer is available
    00565         if (hostmsgbuf == 0)
    00566             break;
    00567
    00568         // And now clears it in the hostbuf array
    00569         ipc_shared_env.msg_e2a_hostbuf_addr[ipc_emb_env.ipc_msge2a_buf_idx] = 0;
    00570
    00571         // Increase the buffer index
    00572         ipc_emb_env.ipc_msge2a_buf_idx = (ipc_emb_env.ipc_msge2a_buf_idx + 1)%IPC_MSGE2A_BUF_CNT;
    00573     } while(0);
    00574
    00575     return hostmsgbuf;
    00576 }
    00577
    00590 static uint32_t ipc_emb_hostdbgbuf_get(void)
    00591 {
    00592     uint32_t hostdbgbuf;
    00593
    00594     do
    00595     {
    00596         // Retrieve the wished hostbuf address
    00597         hostdbgbuf = ipc_shared_env.dbg_hostbuf_addr[ipc_emb_env.ipc_dbg_buf_idx];
    00598
    00599         // Check if the host buffer is available
    00600         if (hostdbgbuf == 0)
    00601             break;
    00602
    00603         // And now clears it in the hostbuf array
    00604         ipc_shared_env.dbg_hostbuf_addr[ipc_emb_env.ipc_dbg_buf_idx] = 0;
    00605
    00606         // Increase the buffer index
    00607         ipc_emb_env.ipc_dbg_buf_idx = (ipc_emb_env.ipc_dbg_buf_idx + 1)%IPC_DBGBUF_CNT;
    00608     } while(0);
    00609
    00610     return hostdbgbuf;
    00611 }
    00612
    00613 /*
    00614 ****************************************************************************************
    00615 */
    00616 uint32_t ipc_emb_hostdbgdumpbuf_get(void)
    00617 {
    00618     uint32_t hostdbgdumpbuf;
    00619
    00620     do
    00621     {
    00622         // Retrieve the wished hostbuf address
    00623         hostdbgdumpbuf = ipc_shared_env.la_dbginfo_addr;
    00624
    00625         // Check if the host buffer is available
    00626         if (hostdbgdumpbuf == 0)
    00627             break;
    00628
    00629         // And now clears it in the hostbuf array
    00630         ipc_shared_env.la_dbginfo_addr = 0;
    00631     } while(0);
    00632
    00633     return (hostdbgdumpbuf);
    00634 }
    00635
    00636 /*
    00637 ****************************************************************************************
    00638 */
    00639 bool ipc_emb_hostrxbuf_check(void)
    00640 {
    00641     // Acknowledge the RX buffer back IRQ, in case we would need it later because no
    00642     // buffers are available
    00643     ipc_app2emb_ack_clear(IPC_IRQ_A2E_RXBUF_BACK);
    00644
    00645     // Check if the buffer was correctly allocated
    00646     #if (NX_UMAC_PRESENT)
    00647     if (ipc_shared_env.host_rxbuf[ipc_emb_env.ipc_rxbuf_idx].dma_addr == 0)
    00648     #else
    00649     if (ipc_shared_env.host_rxbuf[ipc_emb_env.ipc_rxbuf_idx] == 0)
    00650     #endif //(NX_UMAC_PRESENT)
    00651     {
    00652         // No buffer available, so enable the RX buffer back interrupt to be warned
    00653         // as soon as the host has pushed a new buffer
    00654         ipc_app2emb_unmask_set(IPC_IRQ_A2E_RXBUF_BACK);
    00655
    00656         return (false);
    00657     }
    00658
    00659     return (true);
    00660 }
    00661
    00662 #if (NX_UMAC_PRESENT)
    00663 uint32_t ipc_emb_hostrxbuf_get(uint32_t *host_id)
    00664 #else
    00665 uint32_t ipc_emb_hostrxbuf_get(void)
    00666 #endif //(NX_UMAC_PRESENT)
    00667 {
    00668     uint32_t host_buf_dma_addr;
    00669
    00670     RX_HOSTBUF_IDX_CLR();
    00671     RX_HOSTBUF_IDX_SET(ipc_emb_env.ipc_rxbuf_idx);
    00672
    00673     // Retrieve the wished hostbuf address
    00674     #if (NX_UMAC_PRESENT)
    00675     host_buf_dma_addr = ipc_shared_env.host_rxbuf[ipc_emb_env.ipc_rxbuf_idx].dma_addr;
    00676     #else
    00677     host_buf_dma_addr = ipc_shared_env.host_rxbuf[ipc_emb_env.ipc_rxbuf_idx];
    00678     #endif //(NX_UMAC_PRESENT)
    00679
    00680     // Sanity check - dma_addr shall not be 0 as a ipc_emb_hostrxbuf_check should
    00681     // have been called before to ensure that there is a buffer available
    00682     ASSERT_ERR(host_buf_dma_addr != 0);
    00683
    00684     #if (NX_UMAC_PRESENT)
    00685     // Now clears it in the hostbuf array
    00686     ipc_shared_env.host_rxbuf[ipc_emb_env.ipc_rxbuf_idx].dma_addr = 0;
    00687
    00688     *host_id = ipc_shared_env.host_rxbuf[ipc_emb_env.ipc_rxbuf_idx].hostid;
    00689     #else
    00690     // Now clears it in the hostbuf array
    00691     ipc_shared_env.host_rxbuf[ipc_emb_env.ipc_rxbuf_idx] = 0;
    00692     #endif //(NX_UMAC_PRESENT)
    00693
    00694     // Increase the host buffer index
    00695     ipc_emb_env.ipc_rxbuf_idx = (ipc_emb_env.ipc_rxbuf_idx + 1) % IPC_RXBUF_CNT;
    00696
    00697     return host_buf_dma_addr;
    00698 }
    00699
    00700 #if (NX_UMAC_PRESENT)
    00701 /*
    00702 ****************************************************************************************
    00703 */
    00704 bool ipc_emb_hostrxdesc_check(void)
    00705 {
    00706     // Acknowledge the RX buffer back IRQ, in case we would need it later because no
    00707     // buffers are available
    00708     ipc_app2emb_ack_clear(IPC_IRQ_A2E_RXDESC_BACK);
    00709
    00710     // Check if descriptors are available
    00711     if (ipc_shared_env.host_rxdesc[ipc_emb_env.ipc_rxdesc_idx].dma_addr == 0)
    00712     {
    00713         // No buffer available, so enable the RX buffer back interrupt to be warned
    00714         // as soon as the host has pushed a new buffer
    00715         ipc_app2emb_unmask_set(IPC_IRQ_A2E_RXDESC_BACK);
    00716
    00717         return false;
    00718     }
    00719
    00720     return true;
    00721 }
    00722
    00723 uint32_t ipc_emb_hostrxdesc_get(void)
    00724 {
    00725     uint32_t host_desc_dma_addr;
    00726
    00727     // Retrieve the wished hostbuf address
    00728     host_desc_dma_addr = ipc_shared_env.host_rxdesc[ipc_emb_env.ipc_rxdesc_idx].dma_addr;
    00729
    00730     if (host_desc_dma_addr)
    00731     {
    00732         // Now clears it in the hostbuf array
    00733         ipc_shared_env.host_rxdesc[ipc_emb_env.ipc_rxdesc_idx].dma_addr = 0;
    00734
    00735         // Increase the host descriptor index
    00736         ipc_emb_env.ipc_rxdesc_idx = (ipc_emb_env.ipc_rxdesc_idx + 1) % IPC_RXDESC_CNT;
    00737     }
    00738
    00739     return (host_desc_dma_addr);
    00740 }
    00741 #endif //(NX_UMAC_PRESENT)
    00742
    00743 /*
    00744 ****************************************************************************************
    00745 */
    00746 uint32_t ipc_emb_hostradarbuf_get(void)
    00747 {
    00748     uint32_t hostbuf;
    00749
    00750     do
    00751     {
    00752         // Retrieve the wished hostbuf address
    00753         hostbuf = ipc_shared_env.radarbuf_hostbuf[ipc_emb_env.ipc_radar_buf_idx];
    00754
    00755         // Check if the buffer was correctly allocated
    00756         if (hostbuf == 0)
    00757             break;
    00758
    00759         // Now clears it in the hostbuf array
    00760         ipc_shared_env.radarbuf_hostbuf[ipc_emb_env.ipc_radar_buf_idx] = 0;
    00761
    00762         // Increase the host buffer index
    00763         ipc_emb_env.ipc_radar_buf_idx = (ipc_emb_env.ipc_radar_buf_idx + 1)%IPC_RADARBUF_CNT;
    00764
    00765     } while(0);
    00766
    00767     return hostbuf;
    00768 }
    00769
    00770 #if NX_UF_EN
    00771 uint32_t ipc_emb_hostunsuprxvectbuf_get(void)
    00772 {
    00773     uint32_t hostbuf;
    00774
    00775     // Retrieve the wished hostbuf address
    00776     hostbuf = ipc_shared_env.unsuprxvecbuf_hostbuf[ipc_emb_env.ipc_unsup_rx_vec_buf_idx];
    00777
    00778     if (hostbuf == 0)
    00779         return 0;
    00780
    00781     // Now clears it in the hostbuf array
    00782     ipc_shared_env.unsuprxvecbuf_hostbuf[ipc_emb_env.ipc_unsup_rx_vec_buf_idx] = 0;
    00783
    00784     // Increase the host buffer index
    00785     ipc_emb_env.ipc_unsup_rx_vec_buf_idx = (ipc_emb_env.ipc_unsup_rx_vec_buf_idx + 1)%IPC_UNSUPRXVECBUF_CNT;
    00786
    00787     return hostbuf;
    00788 }
    00789 #endif
    00790
    00791 /*
    00792 ****************************************************************************************
    00793 */
    00794 void ipc_emb_rxdata_ind(void)
    00795 {
    00796     // Signal the forwarding of the packet to host by setting a LED
    00797     LED_ON(LED_RX);
    00798
    00799     // For profiling
    00800     PROF_RX_IPC_IND_SET();
    00801
    00802     // Trigger an interrupt the host, indicating a new descriptor is available
    00803     ipc_emb2app_trigger_set(IPC_IRQ_E2A_RXDESC);
    00804
    00805     // For profiling
    00806     PROF_RX_IPC_IND_CLR();
    00807
    00808     // Shut down the RX LED
    00809     LED_OFF(LED_RX);
    00810 }
    00811
    00812 void ipc_emb_radar_event_ind(void)
    00813 {
    00814     // Trigger an interrupt the host, indicating a new radar event is available
    00815     ipc_emb2app_trigger_set(IPC_IRQ_E2A_RADAR);
    00816 }
    00817
    00818 #if NX_UF_EN
    00819 void ipc_emb_unsup_rx_vec_event_ind(void)
    00820 {
    00821     // Trigger an interrupt the host, indicating a new unsupported rx vector is available
    00822     ipc_emb2app_trigger_set(IPC_IRQ_E2A_UNSUP_RX_VEC);
    00823 }
    00824 #endif
    00825
    00826 void ipc_emb_txcfm_ind(uint32_t queue_bits)
    00827 {
    00828     // Trigger an interrupt to the host, indicating a transmission confirmation
    00829     ipc_emb2app_trigger_set(queue_bits << IPC_IRQ_E2A_TXCFM_POS);
    00830 }
    00831
    00832 void ipc_emb_prim_tbtt_ind(void)
    00833 {
    00834     // Trigger an interrupt to the host, indicating the primary TBTT
    00835     ipc_emb2app_trigger_set(IPC_IRQ_E2A_TBTT_PRIM);
    00836 }
    00837
    00838 void ipc_emb_sec_tbtt_ind(void)
    00839 {
    00840     // Trigger an interrupt to the host, indicating the secondary TBTT
    00841     ipc_emb2app_trigger_set(IPC_IRQ_E2A_TBTT_SEC);
    00842 }
    00843
    00852 static void ipc_emb_kmsg_hdlr(struct ke_msg *kmsg_ipc)
    00853 {
    00854     int i;
    00855
    00856     // allocate buffer for incoming msg
    00857     struct ke_msg *kmsg_dst = (struct ke_msg*)
    00858         ke_malloc(sizeof(struct ke_msg) + kmsg_ipc->param_len);
    00859     ASSERT_ERR(kmsg_dst != NULL);
    00860
    00861     kmsg_dst->hdr.next = NULL;
    00862     kmsg_dst->id = kmsg_ipc->id;
    00863     kmsg_dst->dest_id = kmsg_ipc->dest_id;
    00864     kmsg_dst->src_id = TASK_API;
    00865     kmsg_dst->param_len = kmsg_ipc->param_len;
    00866
    00867     // copy parameters
    00868     uint32_t *src = kmsg_ipc->param;
    00869     uint32_t *dst = kmsg_dst->param;
    00870     for (i = 0; i < kmsg_dst->param_len; i+=4)
    00871     {
    00872         *dst++ = *src++;
    00873     }
    00874
    00875     // Read by host for sanity check when ack is received
    00876     kmsg_ipc->src_id = ipc_emb_env.ipc_msgacke2a_cnt++;
    00877
    00878     // message received has no external parameter
    00879     ASSERT_ERR(ke_task_local(kmsg_dst->dest_id));
    00880
    00881     ipc_emb2app_trigger_set(IPC_IRQ_E2A_MSG_ACK);
    00882
    00883     // dispatch the message to the local task
    00884     ke_msg_send(ke_msg2param(kmsg_dst));
    00885 }
    00886
    00887
    00894 void ipc_emb_msg_irq(void)
    00895 {
    00896     PROF_MSG_IRQ_SET();
    00897
    00898     // check HW IPC irq
    00899     if (ipc_app2emb_status_get() & IPC_IRQ_A2E_MSG)
    00900     {
    00901         // set IPC msg event
    00902         ke_evt_set(KE_EVT_MACIF_MSG_BIT);
    00903
    00904         // mask msg IPC irq
    00905         ipc_app2emb_unmask_clear(IPC_IRQ_A2E_MSG);
    00906     }
    00907
    00908     PROF_MSG_IRQ_CLR();
    00909 }
    00910
    00911
    00918 void ipc_emb_msg_evt(int dummy)
    00919 {
    00920     struct ipc_a2e_msg * msg_buf;
    00921
    00922     // read irq raw status (because interrupt could be disabled)
    00923     uint32_t status_irq = ipc_app2emb_rawstatus_get();
    00924
    00925     while (status_irq & IPC_IRQ_A2E_MSG)
    00926     {
    00927         // only ack bits already set!
    00928         ipc_app2emb_ack_clear(IPC_IRQ_A2E_MSG);
    00929
    00930         // Point to the MSG buffer
    00931         msg_buf = (struct ipc_a2e_msg *)&(ipc_shared_env.msg_a2e_buf);
    00932
    00933         // Call the msg handler
    00934         ipc_emb_kmsg_hdlr((struct ke_msg*)msg_buf);
    00935
    00936         status_irq = ipc_app2emb_rawstatus_get();
    00937     }
    00938
    00939     // clear event BEFORE enabling the interrupt
    00940     ke_evt_clear(KE_EVT_MACIF_MSG_BIT);
    00941
    00942     // re-enable the interrupt
    00943     ipc_app2emb_unmask_set(IPC_IRQ_A2E_MSG);
    00944
    00945     return;
    00946 }
    00947
    00948 void ipc_emb_kmsg_fwd(const struct ke_msg *kmsg_src)
    00949 {
    00950     uint32_t host_msg_buf;
    00951     struct ipc_e2a_msg *msg = (struct ipc_e2a_msg *) &(ipc_shared_env.msg_e2a_buf);
    00952     struct dma_desc *msg_dma_desc = (struct dma_desc *) &(ipc_shared_env.msg_dma_desc);
    00953
    00954     PROF_MSG_FWD_SET();
    00955
    00956     // Get the destination address for DMA transfer (host buffer)
    00957     host_msg_buf = ipc_emb_hostmsgbuf_get();
    00958
    00959     // For the time being, put an assertion here
    00960     ASSERT_ERR(host_msg_buf != 0);
    00961
    00962     // Build the real message to be transferred
    00963     msg->id = kmsg_src->id;
    00964     msg->param_len = kmsg_src->param_len * CHAR_LEN;
    00965     // no need to fill the dummy tasks ids in
    00966     if(kmsg_src->param_len != 0)
    00967     {
    00968         ASSERT_ERR(kmsg_src->param_len <= sizeof(msg->param));
    00969         memcpy(msg->param, kmsg_src->param, kmsg_src->param_len);
    00970     }
    00971
    00972     // Free the incoming message now
    00973     ke_msg_free(kmsg_src);
    00974
    00975     // Only one DMA transfer will be needed to send the complete MSG.
    00976     // Configure the unique DMA descriptor (actually the only field that is not constant)
    00977     // - dest: beginning of the host MSG buffer
    00978     msg_dma_desc->dest = host_msg_buf;
    00979
    00980     // Push the DMA descriptor in the DMA engine
    00981     dma_push(msg_dma_desc, msg_dma_desc, IPC_DMA_CHANNEL_CTRL_RX);
    00982
    00983     PROF_MSG_FWD_CLR();
    00984
    00985 }
    00986
    00987 /*
    00988 ****************************************************************************************
    00989 */
    00990 void ipc_emb_msg_dma_int_handler(void)
    00991 {
    00992     PROF_MSG_IPC_IND_SET();
    00993
    00994     // acknowledge the interrupt
    00995     dma_int_ack_clear(CO_BIT(IPC_DMA_LLI_MSG + DMA_LLI_IRQ_LSB));
    00996
    00997     // Trigger an interrupt the host, indicating a new message is available
    00998     ipc_emb2app_trigger_set(IPC_IRQ_E2A_MSG);
    00999
    01000     PROF_MSG_IPC_IND_CLR();
    01001 }
    01002
    01003 /*
    01004 ****************************************************************************************
    01005 */
    01006 void ipc_emb_print_fwd(bool poll, const uint32_t len, char *string)
    01007 {
    01008     uint32_t host_dbg_buf;
    01009     struct ipc_dbg_msg *dbg_msg = (struct ipc_dbg_msg *) &(ipc_shared_env.dbg_buf);
    01010     struct dma_desc *dbg_dma_desc = (struct dma_desc *) &(ipc_shared_env.dbg_dma_desc);
    01011     uint32_t copy_len;
    01012
    01013     // Get the length of the string for the copy (plus 1 because of the NULL terminating
    01014     // string character, to be copied as well)
    01015     copy_len = len + 1;
    01016
    01017     // Get the destination address for DMA transfer (host buffer)
    01018     host_dbg_buf = ipc_emb_hostdbgbuf_get();
    01019
    01020     // No ASSERT in case the address is NULL, the SW will not hang because of Debug
    01021     // (moreover ASSERT also uses Debug strings and would be stuck...)
    01022     if (host_dbg_buf == 0) {
    01023         return;
    01024     }
    01025
    01026     // Check if the string length is not too big, otherwise truncate it to IPC_DBG_PARAM_SIZE
    01027     if (len >= IPC_DBG_PARAM_SIZE)
    01028     {
    01029         string[IPC_DBG_PARAM_SIZE - 3] = '*';
    01030         string[IPC_DBG_PARAM_SIZE - 2] = '\n';
    01031         string[IPC_DBG_PARAM_SIZE - 1] = 0;
    01032         copy_len = IPC_DBG_PARAM_SIZE;
    01033     }
    01034
    01035     // Copy the string
    01036     co_pack8p(CPU2HW(dbg_msg->string), (uint8_t *)string, copy_len);
    01037
    01038     // Only one DMA transfer will be needed to send the complete MSG.
    01039     // Configure the unique DMA descriptor (actually the only field that is not constant)
    01040     // - dest: beginning of the host buffer
    01041     dbg_dma_desc->dest = host_dbg_buf;
    01042
    01043     // Disable interrupts in case we would have to poll
    01044     GLOBAL_INT_DISABLE();
    01045
    01046     // Push the DMA descriptor in the DMA engine
    01047     dma_push(dbg_dma_desc, dbg_dma_desc, IPC_DMA_CHANNEL_CTRL_RX);
    01048
    01049     // Check if we have to poll for the DMA to be finished
    01050     if (poll)
    01051     {
    01052         dma_lli_poll(IPC_DMA_LLI_DBG + DMA_LLI_IRQ_LSB);
    01053
    01054         ipc_emb_dbg_dma_int_handler();
    01055     }
    01056
    01057     // Reenable interrupts
    01058     GLOBAL_INT_RESTORE();
    01059
    01060 }
    01061
    01062 /*
    01063 ****************************************************************************************
    01064 */
    01065 void ipc_emb_dbg_dma_int_handler(void)
    01066 {
    01067     // acknowledge the interrupt
    01068     dma_int_ack_clear(CO_BIT(IPC_DMA_LLI_DBG + DMA_LLI_IRQ_LSB));
    01069
    01070     // Trigger an interrupt the host, indicating a new Debug string is available
    01071     ipc_emb2app_trigger_set(IPC_IRQ_E2A_DBG);
    01072
    01073 }
    01074