summaryrefslogtreecommitdiff
path: root/drivers/net/wireless/eswin/ipc_host.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/eswin/ipc_host.c')
-rw-r--r--drivers/net/wireless/eswin/ipc_host.c784
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;
+}
+