diff options
Diffstat (limited to 'drivers/net/wireless/eswin/ipc_host.c')
-rw-r--r-- | drivers/net/wireless/eswin/ipc_host.c | 784 |
1 files changed, 784 insertions, 0 deletions
diff --git a/drivers/net/wireless/eswin/ipc_host.c b/drivers/net/wireless/eswin/ipc_host.c new file mode 100644 index 000000000000..17ef5c150041 --- /dev/null +++ b/drivers/net/wireless/eswin/ipc_host.c @@ -0,0 +1,784 @@ +/** + ****************************************************************************** + * + * @file ipc_host.c + * + * @brief IPC module. + * + * Copyright (C) ESWIN 2015-2020 + * + ****************************************************************************** + */ + +/* + * INCLUDE FILES + ****************************************************************************** + */ +#ifndef __KERNEL__ +#include <stdio.h> +#define REG_SW_SET_PROFILING(env, value) do{ }while(0) +#define REG_SW_CLEAR_PROFILING(env, value) do{ }while(0) +#define REG_SW_CLEAR_HOSTBUF_IDX_PROFILING(env) do{ }while(0) +#define REG_SW_SET_HOSTBUF_IDX_PROFILING(env, val) do{ }while(0) +#else +#include <linux/spinlock.h> +#include "ecrnx_defs.h" +#include "ecrnx_prof.h" +#endif + +#include "reg_ipc_app.h" +#include "ipc_host.h" + +#ifdef CONFIG_ECRNX_ESWIN +#include "eswin_utils.h" +#endif + +/* + * TYPES DEFINITION + ****************************************************************************** + */ + +const int nx_txdesc_cnt[] = +{ + NX_TXDESC_CNT0, + NX_TXDESC_CNT1, + NX_TXDESC_CNT2, + NX_TXDESC_CNT3, + #if NX_TXQ_CNT == 5 + NX_TXDESC_CNT4, + #endif +}; + +const int nx_txdesc_cnt_msk[] = +{ + NX_TXDESC_CNT0 - 1, + NX_TXDESC_CNT1 - 1, + NX_TXDESC_CNT2 - 1, + NX_TXDESC_CNT3 - 1, + #if NX_TXQ_CNT == 5 + NX_TXDESC_CNT4 - 1, + #endif +}; + +const int nx_txuser_cnt[] = +{ + CONFIG_USER_MAX, + CONFIG_USER_MAX, + CONFIG_USER_MAX, + CONFIG_USER_MAX, + #if NX_TXQ_CNT == 5 + 1, + #endif +}; + + +/* + * FUNCTIONS DEFINITIONS + ****************************************************************************** + */ +/** + * ipc_host_rxdesc_handler() - Handle the reception of a Rx Descriptor + * + * @env: pointer to the IPC Host environment + * + * Called from general IRQ handler when status %IPC_IRQ_E2A_RXDESC is set + */ +static void ipc_host_rxdesc_handler(struct ipc_host_env_tag *env) +{ + // For profiling + REG_SW_SET_PROFILING(env->pthis, SW_PROF_IRQ_E2A_RXDESC); + + // LMAC has triggered an IT saying that a reception has occurred. + // Then we first need to check the validity of the current hostbuf, and the validity + // of the next hostbufs too, because it is likely that several hostbufs have been + // filled within the time needed for this irq handling + do { + #ifdef CONFIG_ECRNX_FULLMAC + // call the external function to indicate that a RX descriptor is received + if (env->cb.recv_data_ind(env->pthis, + env->ipc_host_rxdesc_array[env->ipc_host_rxdesc_idx].hostid) != 0) + #else + // call the external function to indicate that a RX packet is received + if (env->cb.recv_data_ind(env->pthis, + env->ipc_host_rxbuf_array[env->ipc_host_rxbuf_idx].hostid) != 0) + #endif //(CONFIG_ECRNX_FULLMAC) + break; + + }while(1); + + // For profiling + REG_SW_CLEAR_PROFILING(env->pthis, SW_PROF_IRQ_E2A_RXDESC); +} + +/** + * ipc_host_radar_handler() - Handle the reception of radar events + * + * @env: pointer to the IPC Host environment + * + * Called from general IRQ handler when status %IPC_IRQ_E2A_RADAR is set + */ +static void ipc_host_radar_handler(struct ipc_host_env_tag *env) +{ +#ifdef CONFIG_ECRNX_RADAR + // LMAC has triggered an IT saying that a radar event has been sent to upper layer. + // Then we first need to check the validity of the current msg buf, and the validity + // of the next buffers too, because it is likely that several buffers have been + // filled within the time needed for this irq handling + // call the external function to indicate that a RX packet is received + spin_lock(&((struct ecrnx_hw *)env->pthis)->radar.lock); + while (env->cb.recv_radar_ind(env->pthis, + env->ipc_host_radarbuf_array[env->ipc_host_radarbuf_idx].hostid) == 0) + ; + spin_unlock(&((struct ecrnx_hw *)env->pthis)->radar.lock); +#endif /* CONFIG_ECRNX_RADAR */ +} + +/** + * ipc_host_unsup_rx_vec_handler() - Handle the reception of unsupported rx vector + * + * @env: pointer to the IPC Host environment + * + * Called from general IRQ handler when status %IPC_IRQ_E2A_UNSUP_RX_VEC is set + */ +static void ipc_host_unsup_rx_vec_handler(struct ipc_host_env_tag *env) +{ + while (env->cb.recv_unsup_rx_vec_ind(env->pthis, + env->ipc_host_unsuprxvecbuf_array[env->ipc_host_unsuprxvecbuf_idx].hostid) == 0) + ; +} + +/** + * ipc_host_msg_handler() - Handler for firmware message + * + * @env: pointer to the IPC Host environment + * + * Called from general IRQ handler when status %IPC_IRQ_E2A_MSG is set + */ +static void ipc_host_msg_handler(struct ipc_host_env_tag *env) +{ + // For profiling + REG_SW_SET_PROFILING(env->pthis, SW_PROF_IRQ_E2A_MSG); + + // LMAC has triggered an IT saying that a message has been sent to upper layer. + // Then we first need to check the validity of the current msg buf, and the validity + // of the next buffers too, because it is likely that several buffers have been + // filled within the time needed for this irq handling + // call the external function to indicate that a RX packet is received + while (env->cb.recv_msg_ind(env->pthis, + env->ipc_host_msgbuf_array[env->ipc_host_msge2a_idx].hostid) == 0) + ; + + + // For profiling + REG_SW_CLEAR_PROFILING(env->pthis, SW_PROF_IRQ_E2A_MSG); + +} + +/** + * ipc_host_msgack_handler() - Handle the reception of message acknowledgement + * + * @env: pointer to the IPC Host environment + * + * Called from general IRQ handler when status %IPC_IRQ_E2A_MSG_ACK is set + */ +static void ipc_host_msgack_handler(struct ipc_host_env_tag *env) +{ + void *hostid = env->msga2e_hostid; + + ASSERT_ERR(hostid); + ASSERT_ERR(env->msga2e_cnt == (((struct lmac_msg *)(&env->shared->msg_a2e_buf.msg))->src_id & 0xFF)); + + env->msga2e_hostid = NULL; + env->msga2e_cnt++; + env->cb.recv_msgack_ind(env->pthis, hostid); +} + +/** + * ipc_host_dbg_handler() - Handle the reception of Debug event + * + * @env: pointer to the IPC Host environment + * + * Called from general IRQ handler when status %IPC_IRQ_E2A_DBG is set + */ +static void ipc_host_dbg_handler(struct ipc_host_env_tag *env) +{ + // For profiling + REG_SW_SET_PROFILING(env->pthis, SW_PROF_IRQ_E2A_DBG); + + // LMAC has triggered an IT saying that a DBG message has been sent to upper layer. + // Then we first need to check the validity of the current buffer, and the validity + // of the next buffers too, because it is likely that several buffers have been + // filled within the time needed for this irq handling + // call the external function to indicate that a RX packet is received + while(env->cb.recv_dbg_ind(env->pthis, + env->ipc_host_dbgbuf_array[env->ipc_host_dbg_idx].hostid) == 0) + ; + + // For profiling + REG_SW_CLEAR_PROFILING(env->pthis, SW_PROF_IRQ_E2A_DBG); +} + +/** + * ipc_host_tx_cfm_handler() - Handle the reception of TX confirmation + * + * @env: pointer to the IPC Host environment + * @queue_idx: index of the hardware on which the confirmation has been received + * @user_pos: index of the user position + * + * Called from general IRQ handler when status %IPC_IRQ_E2A_TXCFM is set + */ +static void ipc_host_tx_cfm_handler(struct ipc_host_env_tag *env, + const int queue_idx, const int user_pos) +{ + // TX confirmation descriptors have been received + REG_SW_SET_PROFILING(env->pthis, SW_PROF_IRQ_E2A_TXCFM); + while (1) + { + // Get the used index and increase it. We do the increase before knowing if the + // current buffer is confirmed because the callback function may call the + // ipc_host_txdesc_get() in case flow control was enabled and the index has to be + // already at the good value to ensure that the test of FIFO full is correct + uint32_t used_idx = env->txdesc_used_idx[queue_idx][user_pos]++; + uint32_t used_idx_mod = used_idx & nx_txdesc_cnt_msk[queue_idx]; + void *host_id = env->tx_host_id[queue_idx][user_pos][used_idx_mod]; + + // Reset the host id in the array + env->tx_host_id[queue_idx][user_pos][used_idx_mod] = 0; + + // call the external function to indicate that a TX packet is freed + if (host_id == 0) + { + // No more confirmations, so put back the used index at its initial value + env->txdesc_used_idx[queue_idx][user_pos] = used_idx; + break; + } + + if (env->cb.send_data_cfm(env->pthis, host_id) != 0) + { + // No more confirmations, so put back the used index at its initial value + env->txdesc_used_idx[queue_idx][user_pos] = used_idx; + env->tx_host_id[queue_idx][user_pos][used_idx_mod] = host_id; + // and exit the loop + break; + } + + REG_SW_SET_PROFILING_CHAN(env->pthis, SW_PROF_CHAN_CTXT_CFM_HDL_BIT); + REG_SW_CLEAR_PROFILING_CHAN(env->pthis, SW_PROF_CHAN_CTXT_CFM_HDL_BIT); + } + + REG_SW_CLEAR_PROFILING(env->pthis, SW_PROF_IRQ_E2A_TXCFM); +} + +/** + ****************************************************************************** + */ +bool ipc_host_tx_frames_pending(struct ipc_host_env_tag *env) +{ + int i, j; + bool tx_frames_pending = false; + + for (i = 0; (i < IPC_TXQUEUE_CNT) && !tx_frames_pending; i++) + { + for (j = 0; j < nx_txuser_cnt[i]; j++) + { + uint32_t used_idx = env->txdesc_used_idx[i][j]; + uint32_t free_idx = env->txdesc_free_idx[i][j]; + + // Check if this queue is empty or not + if (used_idx != free_idx) + { + // The queue is not empty, update the flag and exit + tx_frames_pending = true; + break; + } + } + } + + return (tx_frames_pending); +} + +/** + ****************************************************************************** + */ +void *ipc_host_tx_flush(struct ipc_host_env_tag *env, const int queue_idx, const int user_pos) +{ + uint32_t used_idx = env->txdesc_used_idx[queue_idx][user_pos]; + void *host_id = env->tx_host_id[queue_idx][user_pos][used_idx & nx_txdesc_cnt_msk[queue_idx]]; + + // call the external function to indicate that a TX packet is freed + if (host_id != 0) + { + // Reset the host id in the array + env->tx_host_id[queue_idx][user_pos][used_idx & nx_txdesc_cnt_msk[queue_idx]] = 0; + + // Increment the used index + env->txdesc_used_idx[queue_idx][user_pos]++; + } + + return (host_id); +} + +/** + ****************************************************************************** + */ +void ipc_host_init(struct ipc_host_env_tag *env, + struct ipc_host_cb_tag *cb, + struct ipc_shared_env_tag *shared_env_ptr, + void *pthis) +{ + unsigned int i; + unsigned int size; + unsigned int * dst; + + // Reset the environments + // Reset the IPC Shared memory +#if 0 + /* check potential platform bug on multiple stores */ + memset(shared_env_ptr, 0, sizeof(struct ipc_shared_env_tag)); +#else + dst = (unsigned int *)shared_env_ptr; + size = (unsigned int)sizeof(struct ipc_shared_env_tag); + for (i=0; i < size; i+=4) + { + *dst++ = 0; + } +#endif + // Reset the IPC Host environment + memset(env, 0, sizeof(struct ipc_host_env_tag)); + + // Initialize the shared environment pointer + env->shared = shared_env_ptr; + + // Save the callbacks in our own environment + env->cb = *cb; + + // Save the pointer to the register base + env->pthis = pthis; + + // Initialize buffers numbers and buffers sizes needed for DMA Receptions + env->rx_bufnb = IPC_RXBUF_CNT; + #ifdef CONFIG_ECRNX_FULLMAC + env->rxdesc_nb = IPC_RXDESC_CNT; + #endif //(CONFIG_ECRNX_FULLMAC) + env->radar_bufnb = IPC_RADARBUF_CNT; + env->radar_bufsz = sizeof(struct radar_pulse_array_desc); + env->unsuprxvec_bufnb = IPC_UNSUPRXVECBUF_CNT; + env->unsuprxvec_bufsz = max(sizeof(struct rx_vector_desc), (size_t) RADIOTAP_HDR_MAX_LEN) + + RADIOTAP_HDR_VEND_MAX_LEN + UNSUP_RX_VEC_DATA_LEN; + env->ipc_e2amsg_bufnb = IPC_MSGE2A_BUF_CNT; + env->ipc_e2amsg_bufsz = sizeof(struct ipc_e2a_msg); + env->ipc_dbg_bufnb = IPC_DBGBUF_CNT; + env->ipc_dbg_bufsz = sizeof(struct ipc_dbg_msg); + + for (i = 0; i < CONFIG_USER_MAX; i++) + { + // Initialize the pointers to the hostid arrays + env->tx_host_id[0][i] = env->tx_host_id0[i]; + env->tx_host_id[1][i] = env->tx_host_id1[i]; + env->tx_host_id[2][i] = env->tx_host_id2[i]; + env->tx_host_id[3][i] = env->tx_host_id3[i]; + #if NX_TXQ_CNT == 5 + env->tx_host_id[4][i] = NULL; + #endif + + // Initialize the pointers to the TX descriptor arrays + env->txdesc[0][i] = shared_env_ptr->txdesc0[i]; + env->txdesc[1][i] = shared_env_ptr->txdesc1[i]; + env->txdesc[2][i] = shared_env_ptr->txdesc2[i]; + env->txdesc[3][i] = shared_env_ptr->txdesc3[i]; + #if NX_TXQ_CNT == 5 + env->txdesc[4][i] = NULL; + #endif + } + + #if NX_TXQ_CNT == 5 + env->tx_host_id[4][0] = env->tx_host_id4[0]; + env->txdesc[4][0] = shared_env_ptr->txdesc4[0]; + #endif +} + +/** + ****************************************************************************** + */ +void ipc_host_patt_addr_push(struct ipc_host_env_tag *env, uint32_t addr) +{ + struct ipc_shared_env_tag *shared_env_ptr = env->shared; + + // Copy the address + shared_env_ptr->pattern_addr = addr; +} + +/** + ****************************************************************************** + */ +int ipc_host_rxbuf_push(struct ipc_host_env_tag *env, +#ifdef CONFIG_ECRNX_SOFTMAC + void *hostid, +#else + uint32_t hostid, +#endif + uint32_t hostbuf) +{ + struct ipc_shared_env_tag *shared_env_ptr = env->shared; + + REG_SW_CLEAR_HOSTBUF_IDX_PROFILING(env->pthis); + REG_SW_SET_HOSTBUF_IDX_PROFILING(env->pthis, env->ipc_host_rxbuf_idx); + +#ifdef CONFIG_ECRNX_FULLMAC + // Copy the hostbuf (DMA address) in the ipc shared memory + shared_env_ptr->host_rxbuf[env->ipc_host_rxbuf_idx].hostid = hostid; + shared_env_ptr->host_rxbuf[env->ipc_host_rxbuf_idx].dma_addr = hostbuf; +#else + // Save the hostid and the hostbuf in global array + env->ipc_host_rxbuf_array[env->ipc_host_rxbuf_idx].hostid = hostid; + env->ipc_host_rxbuf_array[env->ipc_host_rxbuf_idx].dma_addr = hostbuf; + + shared_env_ptr->host_rxbuf[env->ipc_host_rxbuf_idx] = hostbuf; +#endif //(CONFIG_ECRNX_FULLMAC) + + // Signal to the embedded CPU that at least one buffer is available + ipc_app2emb_trigger_set(shared_env_ptr, IPC_IRQ_A2E_RXBUF_BACK); + + // Increment the array index + env->ipc_host_rxbuf_idx = (env->ipc_host_rxbuf_idx +1)%IPC_RXBUF_CNT; + + return (0); +} + +#ifdef CONFIG_ECRNX_FULLMAC +/** + ****************************************************************************** + */ +int ipc_host_rxdesc_push(struct ipc_host_env_tag *env, void *hostid, + uint32_t hostbuf) +{ + struct ipc_shared_env_tag *shared_env_ptr = env->shared; + + // Reset the RX Descriptor DMA Address and increment the counter + env->ipc_host_rxdesc_array[env->ipc_host_rxdesc_idx].dma_addr = hostbuf; + env->ipc_host_rxdesc_array[env->ipc_host_rxdesc_idx].hostid = hostid; + + shared_env_ptr->host_rxdesc[env->ipc_host_rxdesc_idx].dma_addr = hostbuf; + + // Signal to the embedded CPU that at least one descriptor is available + ipc_app2emb_trigger_set(shared_env_ptr, IPC_IRQ_A2E_RXDESC_BACK); + + env->ipc_host_rxdesc_idx = (env->ipc_host_rxdesc_idx + 1) % IPC_RXDESC_CNT; + + return (0); +} +#endif /* CONFIG_ECRNX_FULLMAC */ + +/** + ****************************************************************************** + */ +int ipc_host_radarbuf_push(struct ipc_host_env_tag *env, void *hostid, + uint32_t hostbuf) +{ + struct ipc_shared_env_tag *shared_env_ptr = env->shared; + + // Save the hostid and the hostbuf in global array + env->ipc_host_radarbuf_array[env->ipc_host_radarbuf_idx].hostid = hostid; + env->ipc_host_radarbuf_array[env->ipc_host_radarbuf_idx].dma_addr = hostbuf; + + // Copy the hostbuf (DMA address) in the ipc shared memory + shared_env_ptr->radarbuf_hostbuf[env->ipc_host_radarbuf_idx] = hostbuf; + + // Increment the array index + env->ipc_host_radarbuf_idx = (env->ipc_host_radarbuf_idx +1)%IPC_RADARBUF_CNT; + + return (0); +} + +/** + ****************************************************************************** + */ + +int ipc_host_unsup_rx_vec_buf_push(struct ipc_host_env_tag *env, + void *hostid, + uint32_t hostbuf) +{ + struct ipc_shared_env_tag *shared_env_ptr = env->shared; + + env->ipc_host_unsuprxvecbuf_array[env->ipc_host_unsuprxvecbuf_idx].hostid = hostid; + env->ipc_host_unsuprxvecbuf_array[env->ipc_host_unsuprxvecbuf_idx].dma_addr = hostbuf; + + // Copy the hostbuf (DMA address) in the ipc shared memory + shared_env_ptr->unsuprxvecbuf_hostbuf[env->ipc_host_unsuprxvecbuf_idx] = hostbuf; + + // Increment the array index + env->ipc_host_unsuprxvecbuf_idx = (env->ipc_host_unsuprxvecbuf_idx + 1)%IPC_UNSUPRXVECBUF_CNT; + + return (0); +} + +/** + ****************************************************************************** + */ +int ipc_host_msgbuf_push(struct ipc_host_env_tag *env, void *hostid, + uint64_t hostbuf) +{ + struct ipc_shared_env_tag *shared_env_ptr = env->shared; + + // Save the hostid and the hostbuf in global array + env->ipc_host_msgbuf_array[env->ipc_host_msge2a_idx].hostid = hostid; + env->ipc_host_msgbuf_array[env->ipc_host_msge2a_idx].dma_addr = hostbuf; + + // Copy the hostbuf (DMA address) in the ipc shared memory + shared_env_ptr->msg_e2a_hostbuf_addr[env->ipc_host_msge2a_idx] = hostbuf; + + // Increment the array index + env->ipc_host_msge2a_idx = (env->ipc_host_msge2a_idx +1)%IPC_MSGE2A_BUF_CNT; + + return (0); +} + +/** + ****************************************************************************** + */ +int ipc_host_dbgbuf_push(struct ipc_host_env_tag *env, void *hostid, + uint64_t hostbuf) +{ + struct ipc_shared_env_tag *shared_env_ptr = env->shared; + + // Save the hostid and the hostbuf in global array + env->ipc_host_dbgbuf_array[env->ipc_host_dbg_idx].hostid = hostid; + env->ipc_host_dbgbuf_array[env->ipc_host_dbg_idx].dma_addr = hostbuf; + + // Copy the hostbuf (DMA address) in the ipc shared memory + shared_env_ptr->dbg_hostbuf_addr[env->ipc_host_dbg_idx] = hostbuf; + + // Increment the array index + env->ipc_host_dbg_idx = (env->ipc_host_dbg_idx +1)%IPC_DBGBUF_CNT; + + return (0); +} + +/** + ****************************************************************************** + */ +void ipc_host_dbginfobuf_push(struct ipc_host_env_tag *env, uint32_t infobuf) +{ + struct ipc_shared_env_tag *shared_env_ptr = env->shared; + + // Copy the hostbuf (DMA address) in the ipc shared memory + shared_env_ptr->la_dbginfo_addr = infobuf; +} + +/** + ****************************************************************************** + */ +volatile struct txdesc_host *ipc_host_txdesc_get(struct ipc_host_env_tag *env, const int queue_idx, const int user_pos) +{ + volatile struct txdesc_host *txdesc_free; + uint32_t used_idx = env->txdesc_used_idx[queue_idx][user_pos]; + uint32_t free_idx = env->txdesc_free_idx[queue_idx][user_pos]; + + ASSERT_ERR(queue_idx < IPC_TXQUEUE_CNT); + ASSERT_ERR((free_idx - used_idx) <= nx_txdesc_cnt[queue_idx]); + + // Check if a free descriptor is available + if (free_idx != (used_idx + nx_txdesc_cnt[queue_idx])) + { + // Get the pointer to the first free descriptor + txdesc_free = env->txdesc[queue_idx][user_pos] + (free_idx & nx_txdesc_cnt_msk[queue_idx]); + } + else + { + txdesc_free = NULL; + } + + return txdesc_free; +} + +/** + ****************************************************************************** + */ +void ipc_host_txdesc_push(struct ipc_host_env_tag *env, const int queue_idx, + const int user_pos, void *host_id) +{ + uint32_t free_idx = env->txdesc_free_idx[queue_idx][user_pos] & nx_txdesc_cnt_msk[queue_idx]; + volatile struct txdesc_host *txdesc_pushed = env->txdesc[queue_idx][user_pos] + free_idx; + + + // Descriptor is now ready + txdesc_pushed->ready = 0xFFFFFFFF; + + // Save the host id in the environment + env->tx_host_id[queue_idx][user_pos][free_idx] = host_id; + + // Increment the index + env->txdesc_free_idx[queue_idx][user_pos]++; + + // trigger interrupt!!! + //REG_SW_SET_PROFILING(env->pthis, CO_BIT(queue_idx+SW_PROF_IRQ_A2E_TXDESC_FIRSTBIT)); + ipc_app2emb_trigger_setf(env->shared, CO_BIT(user_pos + queue_idx * CONFIG_USER_MAX + + IPC_IRQ_A2E_TXDESC_FIRSTBIT)); +} + +/** + ****************************************************************************** + */ +void ipc_host_irq(struct ipc_host_env_tag *env, uint32_t status) +{ + // Acknowledge the pending interrupts + ipc_emb2app_ack_clear(env->shared, status); + // And re-read the status, just to be sure that the acknowledgment is + // effective when we start the interrupt handling + ipc_emb2app_status_get(env->shared); + + // Optimized for only one IRQ at a time + if (status & IPC_IRQ_E2A_RXDESC) + { + // handle the RX descriptor reception + ipc_host_rxdesc_handler(env); + } + if (status & IPC_IRQ_E2A_MSG_ACK) + { + ipc_host_msgack_handler(env); + } + if (status & IPC_IRQ_E2A_MSG) + { + ipc_host_msg_handler(env); + } + if (status & IPC_IRQ_E2A_TXCFM) + { + int i; + +#ifdef __KERNEL__ + spin_lock(&((struct ecrnx_hw *)env->pthis)->tx_lock); +#endif + // handle the TX confirmation reception + for (i = 0; i < IPC_TXQUEUE_CNT; i++) + { + int j = 0; +#ifdef CONFIG_ECRNX_MUMIMO_TX + for (; j < nx_txuser_cnt[i]; j++) +#endif + { + uint32_t q_bit = CO_BIT(j + i * CONFIG_USER_MAX + IPC_IRQ_E2A_TXCFM_POS); + if (status & q_bit) + { + // handle the confirmation + ipc_host_tx_cfm_handler(env, i, j); + } + } + } +#ifdef __KERNEL__ + spin_unlock(&((struct ecrnx_hw *)env->pthis)->tx_lock); +#endif + } + if (status & IPC_IRQ_E2A_RADAR) + { + // handle the radar event reception + ipc_host_radar_handler(env); + } + + if (status & IPC_IRQ_E2A_UNSUP_RX_VEC) + { + // handle the unsupported rx vector reception + ipc_host_unsup_rx_vec_handler(env); + } + + if (status & IPC_IRQ_E2A_DBG) + { + ipc_host_dbg_handler(env); + } + + if (status & IPC_IRQ_E2A_TBTT_PRIM) + { + env->cb.prim_tbtt_ind(env->pthis); + } + + if (status & IPC_IRQ_E2A_TBTT_SEC) + { + env->cb.sec_tbtt_ind(env->pthis); + } +} + +/** + ****************************************************************************** + */ +int ipc_host_msg_push(struct ipc_host_env_tag *env, void *msg_buf, uint16_t len) +{ +#ifndef CONFIG_ECRNX_ESWIN + int i; + uint32_t *src, *dst; +#endif + + REG_SW_SET_PROFILING(env->pthis, SW_PROF_IPC_MSGPUSH); + + ASSERT_ERR(!env->msga2e_hostid); + ASSERT_ERR(round_up(len, 4) <= sizeof(env->shared->msg_a2e_buf.msg)); + +#ifndef CONFIG_ECRNX_ESWIN + // Copy the message into the IPC MSG buffer +#ifdef __KERNEL__ + src = (uint32_t*)((struct ecrnx_cmd *)msg_buf)->a2e_msg; +#else + src = (uint32_t*) msg_buf; +#endif + dst = (uint32_t*)&(env->shared->msg_a2e_buf.msg); + + // Copy the message in the IPC queue + for (i=0; i<len; i+=4) + { + *dst++ = *src++; + } + + env->msga2e_hostid = msg_buf; + + // Trigger the irq to send the message to EMB + ipc_app2emb_trigger_set(env->shared, IPC_IRQ_A2E_MSG); +#else + env->msga2e_hostid = msg_buf; + ecrnx_msg_send(msg_buf, len); +#endif + + REG_SW_CLEAR_PROFILING(env->pthis, SW_PROF_IPC_MSGPUSH); + + return (0); +} + +/** + ****************************************************************************** + */ +void ipc_host_enable_irq(struct ipc_host_env_tag *env, uint32_t value) +{ + // Enable the handled interrupts + ipc_emb2app_unmask_set(env->shared, value); +} + +/** + ****************************************************************************** + */ +void ipc_host_disable_irq(struct ipc_host_env_tag *env, uint32_t value) +{ + // Enable the handled interrupts + ipc_emb2app_unmask_clear(env->shared, value); +} + +/** + ****************************************************************************** + */ +uint32_t ipc_host_get_status(struct ipc_host_env_tag *env) +{ + volatile uint32_t status; + + status = ipc_emb2app_status_get(env->shared); + + return status; +} + +/** + ****************************************************************************** + */ +uint32_t ipc_host_get_rawstatus(struct ipc_host_env_tag *env) +{ + volatile uint32_t rawstatus; + + rawstatus = ipc_emb2app_rawstatus_get(env->shared); + + return rawstatus; +} + |