/******************************************************************************* * Copyright (C) 2018 Cadence Design Systems, Inc. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to use this Software with Cadence processor cores only and * not with any other processors and platforms, subject to * the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ******************************************************************************/ /******************************************************************************* * xf-msg.h * * Internal messages, and message queues. * *******************************************************************************/ #ifndef __XF_H #error "xf-msg.h mustn't be included directly" #endif /******************************************************************************* * Types definitions ******************************************************************************/ /* ...forward declaration */ typedef struct xf_message xf_message_t; /* ...audio command/response message (internal to DSP processing framework) */ struct xf_message { /* ...pointer to next item in the list */ xf_message_t *next; /* ...shmem session_id */ u32 id; /* ...operation code */ u32 opcode; /* ...length of attached message buffer */ u32 length; /* ...message buffer (translated virtual address) */ void *buffer; #ifndef XAF_ENABLE_NON_HIKEY uint64_t v_buffer; #endif }; /* ...cache-line aligned message buffer */ XF_ALIGNED_TYPEDEF(xf_message_t, __xf_message_t); /* ...message pool definition */ typedef struct xf_msg_pool { /* ...array of aligned messages */ __xf_message_t *p; /* ...pointer to first free item in the pool */ __xf_message_t *head; /* ...total size of the pool */ u32 n; } xf_msg_pool_t; /* ...message accessor */ static inline xf_message_t * xf_msg_pool_item(xf_msg_pool_t *pool, u32 i) { return (xf_message_t *) &pool->p[i]; } /******************************************************************************* * Message queue data ******************************************************************************/ /* ...message queue (single-linked FIFO list) */ typedef struct xf_msg_queue { /* ...head of the queue */ xf_message_t *head; /* ...tail pointer */ xf_message_t *tail; } xf_msg_queue_t; /******************************************************************************* * Message queue API ******************************************************************************/ /* ...initialize message queue */ static inline void xf_msg_queue_init(xf_msg_queue_t *queue) { queue->head = queue->tail = NULL; } /* ...push message in FIFO queue */ static inline int xf_msg_enqueue(xf_msg_queue_t *queue, xf_message_t *m) { int empty = (queue->head == NULL); /* ...set list terminating pointer */ m->next = NULL; if (empty) queue->head = m; else queue->tail->next = m; /* ...advance tail pointer */ queue->tail = m; /* ...return emptiness status */ return empty; } #define xf_msg_enqueue(queue, m) \ ({ \ BUG((m)->next != NULL, _x("message is active: %p"), (m)); \ (xf_msg_enqueue)((queue), (m)); \ }) /* ...retrieve (pop) next message from FIFO queue */ static inline xf_message_t * xf_msg_dequeue(xf_msg_queue_t *queue) { xf_message_t *m = queue->head; /* ...check if there is anything in the queue and dequeue it */ if (m != NULL) { /* ...advance head to the next entry in the queue */ if ((queue->head = m->next) == NULL) queue->tail = NULL; /* ...debug - wipe out next pointer */ m->next = NULL; } return m; } /* ...test if message queue is empty */ static inline int xf_msg_queue_empty(xf_msg_queue_t *queue) { return (queue->head == NULL); } /* ...get message queue head pointer */ static inline xf_message_t * xf_msg_queue_head(xf_msg_queue_t *queue) { return queue->head; } /* ...check if message belongs to a pool */ static inline int xf_msg_from_pool(xf_msg_pool_t *pool, xf_message_t *m) { return (u32)((__xf_message_t*)m - pool->p) < pool->n; } /******************************************************************************* * Global message pool API ******************************************************************************/ /* ...submit message execution on local DSP core */ extern void xf_msg_schedule(xf_message_t *m, u32 ts); /* ...schedule message execution from ISR context */ extern void xf_msg_schedule_isr(xf_message_t *m); /* ...submit message for execution on some DSP */ extern void xf_msg_submit(xf_message_t *m); /* ...cancel local (scheduled on current core) message execution */ extern void xf_msg_cancel(xf_message_t *m); /* ...complete message processing */ extern void xf_msg_complete(xf_message_t *m); /* ...complete message from ISR context */ extern void xf_msg_complete_isr(xf_message_t *m); /* ...allocate message pool on specific core */ extern int xf_msg_pool_init(xf_msg_pool_t *pool, u32 n, u32 core); /* ...allocate message from a pool (no concurrent access from other cores) */ extern xf_message_t * xf_msg_pool_get(xf_msg_pool_t *pool); /* ...return message back to the pool (no concurrent access from other cores) */ extern void xf_msg_pool_put(xf_msg_pool_t *pool, xf_message_t *m); /* ...destroy message pool */ extern void xf_msg_pool_destroy(xf_msg_pool_t *pool, u32 core); /* ...indicate whether pool of free messages is empty */ extern int xf_message_pool_empty(void); /* ...initialize global pool of messages */ extern void xf_message_pool_init(void); /******************************************************************************* * Auxiliary helpers ******************************************************************************/ /* ...send response message to caller */ static inline void xf_response(xf_message_t *m) { xf_msg_complete(m); } /* ...send response message with output buffer */ static inline void xf_response_data(xf_message_t *m, u32 length) { /* ...adjust message output buffer */ m->length = length; /* ...return message to originator */ xf_msg_complete(m); } /* ...send generic "ok" message (no data buffer) */ static inline void xf_response_ok(xf_message_t *m) { /* ...adjust message output buffer */ m->length = 0; /* ...return message to originator */ xf_msg_complete(m); } /* ...send error-response message */ static inline void xf_response_err(xf_message_t *m) { /* ...set generic error message */ m->opcode = XF_UNREGISTER, m->length = 0; /* ...return message to originator */ xf_msg_complete(m); }