blob: 3d355e0c23a9d0e1f678536cab5ee4d242f37f27 [file] [log] [blame]
/*
* Copyright (c) 2025 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef IPC_SERVICE_H
#define IPC_SERVICE_H
#include <zephyr/device.h>
#include <zephyr/ipc/ipc_service.h>
#include "spsc_qm.h"
#define GET_IPC_INSTANCE(dev) (dev)
typedef struct device ipc_device_wrapper_t;
#include <stdint.h>
#include <stdbool.h>
/*
* Must be large enough to contain the internal struct (spsc_pbuf struct) and
* at least two bytes of data (one is reserved for written message length)
*/
#define _MIN_SPSC_SIZE (sizeof(spsc_queue_t) + sizeof(uint32_t))
/*
* TODO: Unsure why some additional bytes are needed for overhead.
*/
#define WIFI_IPC_GET_SPSC_SIZE(x) (_MIN_SPSC_SIZE + 12 + (x))
/* 4 x cmd location 32-bit pointers of 400 bytes each */
#define WIFI_IPC_CMD_SIZE 400
#define WIFI_IPC_CMD_NUM 4
#define WIFI_IPC_CMD_SPSC_SIZE WIFI_IPC_GET_SPSC_SIZE(WIFI_IPC_CMD_NUM * sizeof(uint32_t))
/* 7 x event location 32-bit pointers of 1000 bytes each */
#define WIFI_IPC_EVENT_SIZE 1000
#define WIFI_IPC_EVENT_NUM 7
#define WIFI_IPC_EVENT_SPSC_SIZE WIFI_IPC_GET_SPSC_SIZE(WIFI_IPC_EVENT_NUM * sizeof(uint32_t))
/**
* @enum wifi_ipc_status_t
* @brief Status codes for the Wi-Fi IPC service.
*
* This enumeration defines various status codes that represent
* the state or result of operations in the Wi-Fi IPC service.
*/
typedef enum {
/** Status indicating the operation completed successfully. */
WIFI_IPC_STATUS_OK = 0,
/** Error indicating failure to register IPC service for the Busy queue. */
WIFI_IPC_STATUS_INIT_ERR,
/** Error indicating that the Free queue has not been initialized. */
WIFI_IPC_STATUS_FREEQ_UNINIT_ERR,
/** Status indicating that the Free queue is empty. */
WIFI_IPC_STATUS_FREEQ_EMPTY,
/** Error indicating that the value passed to wifi_ipc_busyq_send()
* does not match the value from the Free queue.
*/
WIFI_IPC_STATUS_FREEQ_INVALID,
/** Status indicating that the Free queue is full. */
WIFI_IPC_STATUS_FREEQ_FULL,
/** Error indicating that the IPC service for the Busy queue connection
* has not been established.
*/
WIFI_IPC_STATUS_BUSYQ_NOTREADY,
/** Status indicating that the Busy queue is full. */
WIFI_IPC_STATUS_BUSYQ_FULL,
/** Critical error indicating an IPC transfer failure. This should never happen. */
WIFI_IPC_STATUS_BUSYQ_CRITICAL_ERR,
} wifi_ipc_status_t;
/**
* Structure to hold context information for busy queue.
*/
typedef struct {
const ipc_device_wrapper_t *ipc_inst;
struct ipc_ept ipc_ep;
struct ipc_ept_cfg ipc_ep_cfg;
void (*recv_cb)(const void *data, const void *priv);
const void *priv;
volatile bool ipc_ready;
} wifi_ipc_busyq_t;
/**
* Top-level structure to hold context information for sending data between RPU
* and the Host.
*/
typedef struct {
spsc_queue_t *free_q;
wifi_ipc_busyq_t busy_q;
wifi_ipc_busyq_t *linked_ipc;
} wifi_ipc_t;
/**
* Performs memory-to-memory copy via MVDMA.
*
* Enters low power state by issuing wait-for-interrupt (WFI) while waiting for
* MVDMA event to complete.
*
* @param[in] p_dest : Pointer to destination memory to be copied to.
* @param[in] p_src : Pointer to source memory to be copied from.
* @param[in] len : Number of bytes to be copied.
*/
void wifi_ipc_mvdma_copy(void *p_dest, const void *p_src, size_t len);
/**
* Bind either TX or RX context to one IPC service. This utilises the half-duplex
* capability of the IPC service.
*
* @param[in] p_context : Pointer to wifi_ipc_t struct.
* @param[in] ipc_inst : Pointer to the IPC instance.
* @param[in] rx_cb : If binding RX context, this is the callback function.
* Leave NULL if binding to a TX.
* @param[in] priv : If binding RX context, this is the private data to be passed
* along with the callback function.
* Leave NULL if binding to a TX.
* @return : wifi_ipc_status_ok if successful, otherwise wifi_ipc_status_init_err.
*/
wifi_ipc_status_t wifi_ipc_bind_ipc_service(wifi_ipc_t *p_context,
const ipc_device_wrapper_t *ipc_inst,
void (*rx_cb)(void *data, void *priv), void *priv);
/**
* Bind both TX and RX contexts to a single IPC service. This utilises the
* full-duplex capability of the IPC service.
*
* @param[in] p_tx : Pointer to wifi_ipc_t struct to bind IPC TX mailbox to.
* @param[in] p_rx : Pointer to wifi_ipc_t struct to bind IPC RX mailbox to.
* @param[in] ipc_inst : Pointer to the IPC instance.
* @param[in] rx_cb : Callback function to bind to data in received from RX mailbox.
* @param[in] priv : Private data to the callback function.
* @return : wifi_ipc_status_ok if successful, otherwise wifi_ipc_status_init_err.
*/
wifi_ipc_status_t wifi_ipc_bind_ipc_service_tx_rx(wifi_ipc_t *p_tx, wifi_ipc_t *p_rx,
const ipc_device_wrapper_t *ipc_inst,
void (*rx_cb)(void *data, void *priv),
void *priv);
/**
* Get data from the free queue.
*
* @param[in] p_context : Pointer to wifi_ipc_t struct.
* @param[out] data : Pointer to the data to read to.
* @return : wifi_ipc_status_ok if successful, otherwise wifi_ipc_status_freeq_empty.
*/
wifi_ipc_status_t wifi_ipc_freeq_get(wifi_ipc_t *p_context, uint32_t *data);
/**
* Send data to the free queue.
*
* @param[in] p_context : Pointer to wifi_ipc_t struct.
* @param[in] data : 32-bit data to send.
* @return : wifi_ipc_status_ok if successful, otherwise wifi_ipc_status_freeq_full.
*/
wifi_ipc_status_t wifi_ipc_freeq_send(wifi_ipc_t *p_context, uint32_t data);
/**
* Send data to the busy queue over IPC service, and pop the same data from the
* free queue.
*
* @param[in] p_context : Pointer to wifi_ipc_t struct.
* @param[in] data : Pointer to the data to send to.
* @return : wifi_ipc_status_ok if successful, otherwise one of the following:
* - wifi_ipc_status_busyq_notready
* - wifi_ipc_status_busyq_full
* - wifi_ipc_status_busyq_critical_err
* - wifi_ipc_status_freeq_invalid
* - wifi_ipc_status_freeq_empty
*/
wifi_ipc_status_t wifi_ipc_busyq_send(wifi_ipc_t *p_context, uint32_t *data);
/**
* Prepares and initialises the Host for sending a command to RPU.
*
* The free queue points to the already allocated free queue from the RPU.
*
* The busy queue using IPC service must be initialised using @see wifi_ipc_bind_ipc_service()
* or @see wifi_ipc_bind_ipc_service_tx_rx().
*
* @param[in] p_context : Pointer to wifi_ipc_t struct.
* @param[in] addr_freeq : Address of the allocated free queue.
* @return : wifi_ipc_status_ok if successful.
*/
wifi_ipc_status_t wifi_ipc_host_cmd_init(wifi_ipc_t *p_context, uint32_t addr_freeq);
/**
* Prepares and initialises the Host for receiving an event from RPU.
*
* The free queue points to the already allocated free queue from the RPU.
*
* The busy queue using IPC service must be initialised using @see wifi_ipc_bind_ipc_service()
* or @see wifi_ipc_bind_ipc_service_tx_rx().
*
* @param[in] p_context : Pointer to wifi_ipc_t struct.
* @param[in] addr_freeq : Address of the allocated SPSC free queue.
* @return : wifi_ipc_status_ok if successful.
*/
wifi_ipc_status_t wifi_ipc_host_event_init(wifi_ipc_t *p_context, uint32_t addr_freeq);
/**
* Get a command location from the free queue.
*
* @param[in] p_context : Pointer to wifi_ipc_t struct.
* @param[out] p_data : Pointer to data to write event location to.
* @return : wifi_ipc_status_ok if successful, otherwise wifi_ipc_status_freeq_empty.
*/
wifi_ipc_status_t wifi_ipc_host_cmd_get(wifi_ipc_t *p_context, uint32_t *p_data);
/**
* Send an event location pointer to the Host and frees up the event location
* pointer from the free queue.
*
* @param[in] p_context : Pointer to wifi_ipc_t struct.
* @param[in] p_data : Pointer to command location to be sent.
* @return : wifi_ipc_status_ok if successful, otherwise one of the following
* - wifi_ipc_status_busyq_notready
* - wifi_ipc_status_busyq_full
* - wifi_ipc_status_busyq_critical_err
* - wifi_ipc_status_freeq_invalid
* - wifi_ipc_status_freeq_empty
*/
wifi_ipc_status_t wifi_ipc_host_cmd_send(wifi_ipc_t *p_context, uint32_t *p_data);
/**
* Send a command from the Host to RPU using standard memcpy.
*
* 1. Retrieves an address pointer of Packet RAM from the free queue.
* 2. Copies local message to the retrieved address pointer via memcpy.
* 3. Sends the address pointer to the busy queue via IPC service.
* 4. Upon successful transmission, removes the address pointer the free queue.
*
* @param[in] p_context : Pointer to wifi_ipc_t struct.
* @param[in] p_msg : Pointer the local message to be copied to Packet RAM via memcpy.
* @param[in] len : Length of the local message in bytes.
* @return : wifi_ipc_status_ok if send is successful, otherwise one of
* status code from wifi_ipc_status_t will be returned.
*/
wifi_ipc_status_t wifi_ipc_host_cmd_send_memcpy(wifi_ipc_t *p_context, const void *p_msg,
size_t len);
/**
* Send a tx data pointer from the Host to RPU and raises RPU interrupt.
*
* @param[in] p_context : Pointer to wifi_ipc_t struct.
* @param[in] p_msg : Pointer to message.
* @return : wifi_ipc_status_ok if send is successful, otherwise one of
* status code from wifi_ipc_status_t will be returned.
*/
wifi_ipc_status_t wifi_ipc_host_tx_send(wifi_ipc_t *p_context, const void *p_msg);
#endif /* IPC_SERVICE_H */