summaryrefslogtreecommitdiff
path: root/drivers/dsp/syslink/multicore_ipc/messageq.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/dsp/syslink/multicore_ipc/messageq.c')
-rw-r--r--drivers/dsp/syslink/multicore_ipc/messageq.c1643
1 files changed, 1643 insertions, 0 deletions
diff --git a/drivers/dsp/syslink/multicore_ipc/messageq.c b/drivers/dsp/syslink/multicore_ipc/messageq.c
new file mode 100644
index 00000000000..83f3d8e7d8e
--- /dev/null
+++ b/drivers/dsp/syslink/multicore_ipc/messageq.c
@@ -0,0 +1,1643 @@
+/*
+ * messageq.c
+ *
+ * The messageQ module supports the structured sending and receiving of
+ * variable length messages. This module can be used for homogeneous or
+ * heterogeneous multi-processor messaging.
+ *
+ * Copyright (C) 2008-2009 Texas Instruments, Inc.
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ */
+
+/*!
+ * MessageQ provides more sophisticated messaging than other modules. It is
+ * typically used for complex situations such as multi-processor messaging.
+ *
+ * The following are key features of the MessageQ module:
+ * -Writers and readers can be relocated to another processor with no
+ * runtime code changes.
+ * -Timeouts are allowed when receiving messages.
+ * -Readers can determine the writer and reply back.
+ * -Receiving a message is deterministic when the timeout is zero.
+ * -Messages can reside on any message queue.
+ * -Supports zero-copy transfers.
+ * -Can send and receive from any type of thread.
+ * -Notification mechanism is specified by application.
+ * -Allows QoS (quality of service) on message buffer pools. For example,
+ * using specific buffer pools for specific message queues.
+ *
+ * Messages are sent and received via a message queue. A reader is a thread
+ * that gets (reads) messages from a message queue. A writer is a thread that
+ * puts (writes) a message to a message queue. Each message queue has one
+ * reader and can have many writers. A thread may read from or write to
+ * multiple message queues.
+ *
+ * Conceptually, the reader thread owns a message queue. The reader thread
+ * creates a message queue. Writer threads a created message queues to
+ * get access to them.
+ *
+ * Message queues are identified by a system-wide unique name. Internally,
+ * MessageQ uses the NameServer module for managing
+ * these names. The names are used for opening a message queue. Using
+ * names is not required.
+ *
+ * Messages must be allocated from the MessageQ module. Once a message is
+ * allocated, it can be sent on any message queue. Once a message is sent, the
+ * writer loses ownership of the message and should not attempt to modify the
+ * message. Once the reader receives the message, it owns the message. It
+ * may either free the message or re-use the message.
+ *
+ * Messages in a message queue can be of variable length. The only
+ * requirement is that the first field in the definition of a message must be a
+ * MsgHeader structure. For example:
+ * typedef struct MyMsg {
+ * messageq_MsgHeader header;
+ * ...
+ * } MyMsg;
+ *
+ * The MessageQ API uses the messageq_MsgHeader internally. Your application
+ * should not modify or directly access the fields in the messageq_MsgHeader.
+ *
+ * All messages sent via the MessageQ module must be allocated from a
+ * Heap implementation. The heap can be used for
+ * other memory allocation not related to MessageQ.
+ *
+ * An application can use multiple heaps. The purpose of having multiple
+ * heaps is to allow an application to regulate its message usage. For
+ * example, an application can allocate critical messages from one heap of fast
+ * on-chip memory and non-critical messages from another heap of slower
+ * external memory
+ *
+ * MessageQ does support the usage of messages that allocated via the
+ * alloc function. Please refer to the static_msg_init
+ * function description for more details.
+ *
+ * In a multiple processor system, MessageQ communications to other
+ * processors via MessageQ_transport} instances. There must be one and
+ * only one IMessageQ_transport instance for each processor where communication
+ * is desired.
+ * So on a four processor system, each processor must have three
+ * IMessageQ_transport instance.
+ *
+ * The user only needs to create the IMessageQ_transport instances. The
+ * instances are responsible for registering themselves with MessageQ.
+ * This is accomplished via the register_transport function.
+ */
+
+
+
+/* Standard headers */
+#include <linux/types.h>
+#include <linux/module.h>
+
+/* Utilities headers */
+#include <linux/string.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/semaphore.h>
+
+/* Syslink headers */
+#include <syslink/atomic_linux.h>
+
+/* Module level headers */
+#include <nameserver.h>
+#include <multiproc.h>
+#include <transportshm_setup_proxy.h>
+#include <heap.h>
+#include <messageq.h>
+#include <transportshm.h>
+
+
+/* Macro to make a correct module magic number with refCount */
+#define MESSAGEQ_MAKE_MAGICSTAMP(x) ((MESSAGEQ_MODULEID << 12u) | (x))
+
+/* =============================================================================
+ * Globals
+ * =============================================================================
+ */
+/*!
+ * @brief Name of the reserved NameServer used for MessageQ.
+ */
+#define MESSAGEQ_NAMESERVER "MessageQ"
+
+/*! Mask to extract priority setting */
+#define MESSAGEQ_TRANSPORTPRIORITYMASK 0x1
+
+/* =============================================================================
+ * Structures & Enums
+ * =============================================================================
+ */
+/* structure for MessageQ module state */
+struct messageq_module_object {
+ atomic_t ref_count;
+ /* Reference count */
+ void *ns_handle;
+ /* Handle to the local NameServer used for storing GP objects */
+ struct mutex *gate_handle;
+ /* Handle of gate to be used for local thread safety */
+ struct messageq_config cfg;
+ /* Current config values */
+ struct messageq_config default_cfg;
+ /* Default config values */
+ struct messageq_params default_inst_params;
+ /* Default instance creation parameters */
+ void *transports[MULTIPROC_MAXPROCESSORS][MESSAGEQ_NUM_PRIORITY_QUEUES];
+ /* Transport to be set in messageq_register_transport */
+ void **queues; /*messageq_handle *queues;*/
+ /* Grow option */
+ void **heaps; /*Heap_Handle *heaps; */
+ /* Heap to be set in messageq_registerHeap */
+ u16 num_queues;
+ /* Heap to be set in messageq_registerHeap */
+ u16 num_heaps;
+ /* Number of Heaps */
+ bool can_free_queues;
+ /* Grow option */
+ u16 seq_num;
+ /* sequence number */
+};
+
+/* Structure for the Handle for the MessageQ. */
+struct messageq_object {
+ struct messageq_params params;
+ /*! Instance specific creation parameters */
+ u32 queue;
+ /* Unique id */
+ struct list_head normal_list;
+ /* Embedded List objects */
+ struct list_head high_list;
+ /* Embedded List objects */
+ void *ns_key;
+ /* NameServer key */
+ struct semaphore *synchronizer;
+ /* Semaphore used for synchronizing message events */
+ bool unblocked;
+ /* Whether MessageQ is unblocked */
+};
+
+
+static struct messageq_module_object messageq_state = {
+ .ns_handle = NULL,
+ .gate_handle = NULL,
+ .queues = NULL,
+ .heaps = NULL,
+ .num_queues = 1,
+ .num_heaps = 1,
+ .can_free_queues = false,
+ .default_cfg.trace_flag = false,
+ .default_cfg.num_heaps = 1,
+ .default_cfg.max_runtime_entries = 32,
+ .default_cfg.max_name_len = 32,
+ .default_inst_params.synchronizer = NULL
+};
+
+/* Pointer to the MessageQ module state */
+static struct messageq_module_object *messageq_module = &messageq_state;
+
+/* =============================================================================
+ * Constants
+ * =============================================================================
+ */
+/* Used to denote a message that was initialized
+ * with the messageq_static_msg_init function. */
+#define MESSAGEQ_STATICMSG 0xFFFF
+
+
+/* =============================================================================
+ * Forward declarations of internal functions
+ * =============================================================================
+ */
+/* Grow the MessageQ table */
+static u16 _messageq_grow(struct messageq_object *obj);
+
+/* Initializes a message not obtained from MessageQ_alloc */
+static void messageq_msg_init(messageq_msg msg);
+
+/* =============================================================================
+ * APIS
+ * =============================================================================
+ */
+/*
+ * ======== messageq_get_config ========
+ * Purpose:
+ * Function to get the default configuration for the MessageQ
+ * module.
+ *
+ * This function can be called by the application to get their
+ * configuration parameter to MessageQ_setup filled in by the
+ * MessageQ module with the default parameters. If the user does
+ * not wish to make any change in the default parameters, this API
+ * is not required to be called.
+ * the listmp_sharedmemory module.
+ */
+void messageq_get_config(struct messageq_config *cfg)
+{
+ if (WARN_ON(unlikely(cfg == NULL)))
+ goto exit;
+
+ if (likely(atomic_cmpmask_and_lt(&(messageq_module->ref_count),
+ MESSAGEQ_MAKE_MAGICSTAMP(0),
+ MESSAGEQ_MAKE_MAGICSTAMP(1)) == true)) {
+ /* (If setup has not yet been called) */
+ memcpy(cfg, &messageq_module->default_cfg,
+ sizeof(struct messageq_config));
+ } else {
+ memcpy(cfg, &messageq_module->cfg,
+ sizeof(struct messageq_config));
+ }
+ return;
+
+exit:
+ pr_err("messageq_get_config: Argument of type "
+ "(struct messageq_config *) passed is null!\n");
+}
+EXPORT_SYMBOL(messageq_get_config);
+
+/*
+ * ======== messageq_setup ========
+ * Purpose:
+ * Function to setup the MessageQ module.
+ *
+ * This function sets up the MessageQ module. This function must
+ * be called before any other instance-level APIs can be invoked.
+ * Module-level configuration needs to be provided to this
+ * function. If the user wishes to change some specific config
+ * parameters, then MessageQ_getConfig can be called to get the
+ * configuration filled with the default values. After this, only
+ * the required configuration values can be changed. If the user
+ * does not wish to make any change in the default parameters, the
+ * application can simply call MessageQ with NULL parameters.
+ * The default parameters would get automatically used.
+ */
+int messageq_setup(const struct messageq_config *cfg)
+{
+ int status = 0;
+ struct nameserver_params params;
+ struct messageq_config tmpcfg;
+
+ /* This sets the ref_count variable is not initialized, upper 16 bits is
+ * written with module Id to ensure correctness of refCount variable.
+ */
+ atomic_cmpmask_and_set(&messageq_module->ref_count,
+ MESSAGEQ_MAKE_MAGICSTAMP(0),
+ MESSAGEQ_MAKE_MAGICSTAMP(0));
+ if (unlikely(atomic_inc_return(&messageq_module->ref_count)
+ != MESSAGEQ_MAKE_MAGICSTAMP(1))) {
+ return 1;
+ }
+
+ if (unlikely(cfg == NULL)) {
+ messageq_get_config(&tmpcfg);
+ cfg = &tmpcfg;
+ }
+
+ if (WARN_ON(unlikely(cfg->max_name_len == 0))) {
+ status = -EINVAL;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(cfg->max_runtime_entries == 0))) {
+ status = -EINVAL;
+ goto exit;
+ }
+
+ /* User has not provided any gate handle, so create a default
+ * handle for protecting list object */
+ messageq_module->gate_handle = kmalloc(sizeof(struct mutex),
+ GFP_KERNEL);
+ if (unlikely(messageq_module->gate_handle == NULL)) {
+ /*! @retval MESSAGEQ_E_FAIL Failed to create lock! */
+ status = MESSAGEQ_E_FAIL;
+ pr_err("messageq_setup: Failed to create a mutex.\n");
+ status = -ENOMEM;
+ goto exit;
+ }
+ mutex_init(messageq_module->gate_handle);
+
+ memcpy(&messageq_module->cfg, (void *) cfg,
+ sizeof(struct messageq_config));
+ /* Initialize the parameters */
+ nameserver_params_init(&params);
+ params.max_value_len = sizeof(u32);
+ params.max_name_len = cfg->max_name_len;
+ params.max_runtime_entries = cfg->max_runtime_entries;
+
+ messageq_module->seq_num = 0;
+
+ /* Create the nameserver for modules */
+ messageq_module->ns_handle = nameserver_create(MESSAGEQ_NAMESERVER,
+ &params);
+ if (unlikely(messageq_module->ns_handle == NULL)) {
+ /*! @retval MESSAGEQ_E_FAIL Failed to create the
+ * MessageQ nameserver*/
+ status = MESSAGEQ_E_FAIL;
+ pr_err("messageq_setup: Failed to create the messageq"
+ "nameserver!\n");
+ goto exit;
+ }
+
+ messageq_module->num_heaps = cfg->num_heaps;
+ messageq_module->heaps = kzalloc(sizeof(void *) * \
+ messageq_module->num_heaps, GFP_KERNEL);
+ if (unlikely(messageq_module->heaps == NULL)) {
+ status = -ENOMEM;
+ goto exit;
+ }
+
+ messageq_module->num_queues = cfg->max_runtime_entries;
+ messageq_module->queues = kzalloc(sizeof(struct messageq_object *) * \
+ messageq_module->num_queues, GFP_KERNEL);
+ if (unlikely(messageq_module->queues == NULL)) {
+ status = -ENOMEM;
+ goto exit;
+ }
+
+ memset(&(messageq_module->transports), 0, (sizeof(void *) * \
+ MULTIPROC_MAXPROCESSORS * \
+ MESSAGEQ_NUM_PRIORITY_QUEUES));
+ return status;
+
+exit:
+ if (status < 0) {
+ messageq_destroy();
+ pr_err("messageq_setup failed! status = 0x%x\n", status);
+ }
+ return status;
+}
+EXPORT_SYMBOL(messageq_setup);
+
+/* Function to destroy the MessageQ module. */
+int messageq_destroy(void)
+{
+ int status = 0;
+ int tmp_status = 0;
+ u32 i;
+
+ if (unlikely(atomic_cmpmask_and_lt(&(messageq_module->ref_count),
+ MESSAGEQ_MAKE_MAGICSTAMP(0),
+ MESSAGEQ_MAKE_MAGICSTAMP(1)) == true)) {
+ status = -ENODEV;
+ goto exit;
+ }
+
+ if (!(atomic_dec_return(&messageq_module->ref_count)
+ == MESSAGEQ_MAKE_MAGICSTAMP(0))) {
+ status = 1;
+ goto exit;
+ }
+
+ /* Temporarily increment the refcount */
+ atomic_set(&messageq_module->ref_count, MESSAGEQ_MAKE_MAGICSTAMP(1));
+
+ /* Delete any Message Queues that have not been deleted so far. */
+ for (i = 0; i < messageq_module->num_queues; i++) {
+ if (messageq_module->queues[i] != NULL) {
+ tmp_status = \
+ messageq_delete(&(messageq_module->queues[i]));
+ if (unlikely(tmp_status < 0 && status >= 0)) {
+ status = tmp_status;
+ pr_err("messageq_destroy: "
+ "messageq_delete failed for queue %d",
+ i);
+ }
+ }
+ }
+
+ if (likely(messageq_module->ns_handle != NULL)) {
+ /* Delete the nameserver for modules */
+ tmp_status = nameserver_delete(&messageq_module->ns_handle);
+ if (unlikely(tmp_status < 0 && status >= 0)) {
+ status = tmp_status;
+ pr_err("messageq_destroy: nameserver_delete failed");
+ }
+ }
+
+ /* Delete the gate if created internally */
+ if (likely(messageq_module->gate_handle != NULL)) {
+ kfree(messageq_module->gate_handle);
+ messageq_module->gate_handle = NULL;
+ }
+
+ memset(&(messageq_module->transports), 0, (sizeof(void *) * \
+ MULTIPROC_MAXPROCESSORS * MESSAGEQ_NUM_PRIORITY_QUEUES));
+ if (likely(messageq_module->heaps != NULL)) {
+ kfree(messageq_module->heaps);
+ messageq_module->heaps = NULL;
+ }
+ if (likely(messageq_module->queues != NULL)) {
+ kfree(messageq_module->queues);
+ messageq_module->queues = NULL;
+ }
+
+ memset(&messageq_module->cfg, 0, sizeof(struct messageq_config));
+ messageq_module->num_queues = 0;
+ messageq_module->num_heaps = 1;
+ messageq_module->can_free_queues = true;
+ atomic_set(&messageq_module->ref_count, MESSAGEQ_MAKE_MAGICSTAMP(0));
+
+exit:
+ if (status < 0)
+ pr_err("messageq_destroy failed! status = 0x%x\n", status);
+ return status;
+}
+EXPORT_SYMBOL(messageq_destroy);
+
+/* Initialize this config-params structure with supplier-specified
+ * defaults before instance creation. */
+void messageq_params_init(struct messageq_params *params)
+{
+ if (unlikely(atomic_cmpmask_and_lt(&(messageq_module->ref_count),
+ MESSAGEQ_MAKE_MAGICSTAMP(0),
+ MESSAGEQ_MAKE_MAGICSTAMP(1)) == true))
+ goto exit;
+ if (WARN_ON(unlikely(params == NULL))) {
+ pr_err("messageq_params_init failed:Argument of "
+ "type(messageq_params *) is NULL!\n");
+ goto exit;
+ }
+
+ memcpy(params, &(messageq_module->default_inst_params),
+ sizeof(struct messageq_params));
+
+exit:
+ return;
+}
+EXPORT_SYMBOL(messageq_params_init);
+
+/* Creates a new instance of MessageQ module. */
+void *messageq_create(char *name, const struct messageq_params *params)
+{
+ int status = 0;
+ struct messageq_object *obj = NULL;
+ bool found = false;
+ u16 count = 0;
+ int i;
+ u16 start;
+ u16 queueIndex = 0;
+
+ if (unlikely(atomic_cmpmask_and_lt(&(messageq_module->ref_count),
+ MESSAGEQ_MAKE_MAGICSTAMP(0),
+ MESSAGEQ_MAKE_MAGICSTAMP(1)) == true)) {
+ status = -ENODEV;
+ goto exit;
+ }
+
+ /* Create the generic obj */
+ obj = kzalloc(sizeof(struct messageq_object), 0);
+ if (unlikely(obj == NULL)) {
+ status = -ENOMEM;
+ goto exit;
+ }
+
+ status = mutex_lock_interruptible(messageq_module->gate_handle);
+ if (status)
+ goto exit;
+ start = 0; /* Statically allocated objects not supported */
+ count = messageq_module->num_queues;
+ /* Search the dynamic array for any holes */
+ for (i = start; i < count ; i++) {
+ if (messageq_module->queues[i] == NULL) {
+ messageq_module->queues[i] = (void *) obj;
+ queueIndex = i;
+ found = true;
+ break;
+ }
+ }
+ /*
+ * If no free slot was found:
+ * - if no growth allowed, raise an error
+ * - if growth is allowed, grow the array
+ */
+ if (unlikely(found == false)) {
+ /* Growth is always allowed */
+ queueIndex = _messageq_grow(obj);
+ if (unlikely(queueIndex == MESSAGEQ_INVALIDMESSAGEQ)) {
+ mutex_unlock(messageq_module->gate_handle);
+ status = MESSAGEQ_E_FAIL;
+ pr_err("messageq_create: Failed to grow the "
+ "queue array!");
+ goto exit;
+ }
+ }
+
+ if (params != NULL) {
+ /* Populate the params member */
+ memcpy((void *) &obj->params, (void *)params,
+ sizeof(struct messageq_params));
+ if (unlikely(params->synchronizer == NULL))
+ obj->synchronizer = \
+ kzalloc(sizeof(struct semaphore), GFP_KERNEL);
+ else
+ obj->synchronizer = params->synchronizer;
+ } else {
+ /*obj->synchronizer = OsalSemaphore_create(
+ OsalSemaphore_Type_Binary
+ | OsalSemaphore_IntType_Interruptible);*/
+ obj->synchronizer = kzalloc(sizeof(struct semaphore),
+ GFP_KERNEL);
+ }
+ if (unlikely(obj->synchronizer == NULL)) {
+ mutex_unlock(messageq_module->gate_handle);
+ status = MESSAGEQ_E_FAIL;
+ pr_err("messageq_create: Failed to create "
+ "synchronizer semaphore!\n");
+ goto exit;
+ } else {
+ sema_init(obj->synchronizer, 0);
+ }
+ mutex_unlock(messageq_module->gate_handle);
+
+ /* Construct the list object */
+ INIT_LIST_HEAD(&obj->normal_list);
+ INIT_LIST_HEAD(&obj->high_list);
+
+ /* Update processor information */
+ obj->queue = ((u32)(multiproc_self()) << 16) | queueIndex;
+ if (likely(name != NULL)) {
+ obj->ns_key = nameserver_add_uint32(messageq_module->ns_handle,
+ name, obj->queue);
+ if (unlikely(obj->ns_key == NULL)) {
+ status = MESSAGEQ_E_FAIL;
+ pr_err("messageq_create: Failed to add "
+ "the messageq name!\n");
+ }
+ }
+
+ /* Whether messageq is blocked */
+ obj->unblocked = false;
+
+exit:
+ if (unlikely(status < 0)) {
+ messageq_delete((void **)&obj);
+ pr_err("messageq_create failed! status = 0x%x\n", status);
+ }
+ return (void *) obj;
+}
+EXPORT_SYMBOL(messageq_create);
+
+/* Deletes a instance of MessageQ module. */
+int messageq_delete(void **msg_handleptr)
+{
+ int status = 0;
+ int tmp_status = 0;
+ struct messageq_object *obj = NULL;
+ messageq_msg temp_msg;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(
+ &(messageq_module->ref_count),
+ MESSAGEQ_MAKE_MAGICSTAMP(0),
+ MESSAGEQ_MAKE_MAGICSTAMP(1)) == true))) {
+ status = -ENODEV;
+ goto exit;
+ }
+ if (WARN_ON(msg_handleptr == NULL)) {
+ status = -EINVAL;
+ goto exit;
+ }
+ if (WARN_ON(*msg_handleptr == NULL)) {
+ status = -EINVAL;
+ goto exit;
+ }
+
+ obj = (struct messageq_object *) (*msg_handleptr);
+
+ /* Take the local lock */
+ status = mutex_lock_interruptible(messageq_module->gate_handle);
+ if (status)
+ goto exit;
+
+ if (unlikely(obj->ns_key != NULL)) {
+ /* remove from the name serve */
+ status = nameserver_remove_entry(messageq_module->ns_handle,
+ obj->ns_key);
+ if (unlikely(status < 0)) {
+ pr_err("messageq_delete: nameserver_remove_"
+ "entry failed! status = 0x%x", status);
+ }
+ }
+
+ /* Remove all the messages for the message queue's normal_list queue
+ * and free the list */
+ while (true) {
+ if (!list_empty(&obj->normal_list)) {
+ temp_msg = (messageq_msg) (obj->normal_list.next);
+ list_del_init(obj->normal_list.next);
+ } else
+ break;
+ tmp_status = messageq_free(temp_msg);
+ if (unlikely((tmp_status < 0) && (status >= 0))) {
+ status = tmp_status;
+ pr_err("messageq_delete: messageq_free failed"
+ " for normal_list!");
+ }
+ }
+ list_del(&obj->normal_list);
+
+ /* Remove all the messages for the message queue's normal_list queue
+ * and free the list */
+ while (true) {
+ if (!list_empty(&obj->high_list)) {
+ temp_msg = (messageq_msg) (obj->high_list.next);
+ list_del_init(obj->high_list.next);
+ } else
+ break;
+ tmp_status = messageq_free(temp_msg);
+ if (unlikely((tmp_status < 0) && (status >= 0))) {
+ status = tmp_status;
+ pr_err("messageq_delete: messageq_free failed"
+ " for high_list!");
+ }
+ }
+ list_del(&obj->high_list);
+
+ /*if (obj->synchronizer != NULL)
+ status = OsalSemaphore_delete(&obj->synchronizer);*/
+ if (obj->synchronizer != NULL) {
+ kfree(obj->synchronizer);
+ obj->synchronizer = NULL;
+ }
+ /* Clear the MessageQ obj from array. */
+ messageq_module->queues[obj->queue & 0xFFFF] = NULL;
+
+ /* Release the local lock */
+ mutex_unlock(messageq_module->gate_handle);
+
+ /* Now free the obj */
+ kfree(obj);
+ *msg_handleptr = NULL;
+
+exit:
+ if (status < 0)
+ pr_err("messageq_delete failed! status = 0x%x\n", status);
+ return status;
+}
+EXPORT_SYMBOL(messageq_delete);
+
+/* Opens a created instance of MessageQ module. */
+int messageq_open(char *name, u32 *queue_id)
+{
+ int status = 0;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(
+ &(messageq_module->ref_count),
+ MESSAGEQ_MAKE_MAGICSTAMP(0),
+ MESSAGEQ_MAKE_MAGICSTAMP(1)) == true))) {
+ status = -ENODEV;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(name == NULL))) {
+ status = -EINVAL;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(queue_id == NULL))) {
+ status = -EINVAL;
+ goto exit;
+ }
+
+ /* Initialize return queue ID to invalid. */
+ *queue_id = MESSAGEQ_INVALIDMESSAGEQ;
+ status = nameserver_get_uint32(messageq_module->ns_handle, name,
+ queue_id, NULL);
+
+exit:
+ if (status < 0)
+ pr_err("messageq_open failed! status = 0x%x\n", status);
+ return status;
+}
+EXPORT_SYMBOL(messageq_open);
+
+/* Closes previously opened/created instance of MessageQ module. */
+int messageq_close(u32 *queue_id)
+{
+ s32 status = 0;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(
+ &(messageq_module->ref_count),
+ MESSAGEQ_MAKE_MAGICSTAMP(0),
+ MESSAGEQ_MAKE_MAGICSTAMP(1)) == true))) {
+ status = -ENODEV;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(queue_id == NULL))) {
+ pr_err("messageq_close: queue_id passed is NULL!\n");
+ status = -EINVAL;
+ goto exit;
+ }
+
+ *queue_id = MESSAGEQ_INVALIDMESSAGEQ;
+
+exit:
+ if (status < 0)
+ pr_err("messageq_close failed! status = 0x%x\n", status);
+ return status;
+}
+EXPORT_SYMBOL(messageq_close);
+
+/* Retrieve a message */
+int messageq_get(void *messageq_handle, messageq_msg *msg,
+ u32 timeout)
+{
+ int status = 0;
+ struct messageq_object *obj = (struct messageq_object *)messageq_handle;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(
+ &(messageq_module->ref_count),
+ MESSAGEQ_MAKE_MAGICSTAMP(0),
+ MESSAGEQ_MAKE_MAGICSTAMP(1)) == true))) {
+ status = -ENODEV;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(msg == NULL))) {
+ status = -EINVAL;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(obj == NULL))) {
+ status = -EINVAL;
+ goto exit;
+ }
+
+ /* Keep looping while there is no element in the list */
+ /* Take the local lock */
+ status = mutex_lock_interruptible(messageq_module->gate_handle);
+ if (status)
+ goto exit;
+ if (!list_empty(&obj->high_list)) {
+ *msg = (messageq_msg) (obj->high_list.next);
+ list_del_init(obj->high_list.next);
+ }
+ /* Leave the local lock */
+ mutex_unlock(messageq_module->gate_handle);
+ while (*msg == NULL) {
+ status = mutex_lock_interruptible(messageq_module->gate_handle);
+ if (status)
+ goto exit;
+ if (!list_empty(&obj->normal_list)) {
+ *msg = (messageq_msg) (obj->normal_list.next);
+ list_del_init(obj->normal_list.next);
+ }
+ mutex_unlock(messageq_module->gate_handle);
+
+ if (*msg == NULL) {
+ /*
+ * Block until notified. If pend times-out, no message
+ * should be returned to the caller
+ */
+ /*! @retval NULL timeout has occurred */
+ if (obj->synchronizer != NULL) {
+ /* TODO: cater to different timeout values */
+ /*status = OsalSemaphore_pend(
+ obj->synchronizer, timeout); */
+ if (timeout == MESSAGEQ_FOREVER) {
+ if (down_interruptible
+ (obj->synchronizer)) {
+ status = -ERESTARTSYS;
+ }
+ } else {
+ status = down_timeout(obj->synchronizer,
+ msecs_to_jiffies(timeout));
+ }
+ if (status < 0) {
+ *msg = NULL;
+ break;
+ }
+ if (obj->unblocked) {
+ *msg = NULL;
+ status = MESSAGEQ_E_UNBLOCKED;
+ obj->unblocked = false;
+ break;
+ }
+ }
+ status = mutex_lock_interruptible(
+ messageq_module->gate_handle);
+ if (status)
+ goto exit;
+ if (!list_empty(&obj->high_list)) {
+ *msg = (messageq_msg) (obj->high_list.next);
+ list_del_init(obj->high_list.next);
+ }
+ mutex_unlock(messageq_module->gate_handle);
+ }
+ }
+
+exit:
+ if (unlikely((messageq_module->cfg.trace_flag == true) && \
+ ((*msg != NULL) && \
+ (((*msg)->flags & MESSAGEQ_TRACEMASK) != 0)))) {
+ pr_info("messageq_get: *msg = 0x%x seq_num = 0x%x "
+ "src_proc = 0x%x obj = 0x%x\n", (uint)(*msg),
+ ((*msg)->seq_num), ((*msg)->src_proc), (uint)(obj));
+ }
+ if (status < 0 && status != -ETIME)
+ pr_err("messageq_get failed! status = 0x%x\n", status);
+ return status;
+}
+EXPORT_SYMBOL(messageq_get);
+
+/* Count the number of messages in the queue */
+int messageq_count(void *messageq_handle)
+{
+ struct messageq_object *obj = (struct messageq_object *)messageq_handle;
+ int count = 0;
+ struct list_head *elem;
+ int key;
+ s32 status = 0;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(
+ &(messageq_module->ref_count),
+ MESSAGEQ_MAKE_MAGICSTAMP(0),
+ MESSAGEQ_MAKE_MAGICSTAMP(1)) == true))) {
+ status = -ENODEV;
+ goto exit;
+ }
+ if (WARN_ON(obj == NULL)) {
+ status = -EINVAL;
+ pr_err("messageq_count: obj passed is NULL!\n");
+ goto exit;
+ }
+
+ key = mutex_lock_interruptible(messageq_module->gate_handle);
+ if (key < 0)
+ return key;
+
+ list_for_each(elem, &obj->high_list) {
+ count++;
+ }
+ list_for_each(elem, &obj->normal_list) {
+ count++;
+ }
+ mutex_unlock(messageq_module->gate_handle);
+
+exit:
+ if (status < 0)
+ pr_err("messageq_count failed! status = 0x%x", status);
+ return count;
+}
+EXPORT_SYMBOL(messageq_count);
+
+/* Initialize a static message */
+void messageq_static_msg_init(messageq_msg msg, u32 size)
+{
+ s32 status = 0;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(
+ &(messageq_module->ref_count),
+ MESSAGEQ_MAKE_MAGICSTAMP(0),
+ MESSAGEQ_MAKE_MAGICSTAMP(1)) == true))) {
+ status = -ENODEV;
+ goto exit;
+ }
+ if (WARN_ON(msg == NULL)) {
+ pr_err("messageq_static_msg_init: msg is invalid!\n");
+ goto exit;
+ }
+
+ /* Fill in the fields of the message */
+ messageq_msg_init(msg);
+ msg->heap_id = MESSAGEQ_STATICMSG;
+ msg->msg_size = size;
+
+ if (unlikely((messageq_module->cfg.trace_flag == true) || \
+ (((*msg).flags & MESSAGEQ_TRACEMASK) != 0))) {
+ pr_info("messageq_static_msg_init: msg = 0x%x "
+ "seq_num = 0x%x src_proc = 0x%x", (uint)(msg),
+ (msg)->seq_num, (msg)->src_proc);
+ }
+
+exit:
+ if (status < 0) {
+ pr_err("messageq_static_msg_init failed! "
+ "status = 0x%x", status);
+ }
+ return;
+}
+EXPORT_SYMBOL(messageq_static_msg_init);
+
+/* Allocate a message and initial the needed fields (note some
+ * of the fields in the header at set via other APIs or in the
+ * messageq_put function. */
+messageq_msg messageq_alloc(u16 heap_id, u32 size)
+{
+ int status = 0;
+ messageq_msg msg = NULL;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(
+ &(messageq_module->ref_count),
+ MESSAGEQ_MAKE_MAGICSTAMP(0),
+ MESSAGEQ_MAKE_MAGICSTAMP(1)) == true))) {
+ status = -ENODEV;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(heap_id >= messageq_module->num_heaps))) {
+ status = -EINVAL;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(messageq_module->heaps[heap_id] == NULL))) {
+ status = -EINVAL;
+ goto exit;
+ }
+
+ /* Allocate the message. No alignment requested */
+ msg = sl_heap_alloc(messageq_module->heaps[heap_id], size, 0);
+ if (msg == NULL) {
+ status = -ENOMEM;
+ goto exit;
+ }
+
+ /* Fill in the fields of the message */
+ messageq_msg_init(msg);
+ msg->msg_size = size;
+ msg->heap_id = heap_id;
+
+ if (unlikely((messageq_module->cfg.trace_flag == true) || \
+ (((*msg).flags & MESSAGEQ_TRACEMASK) != 0))) {
+ pr_info("messageq_alloc: msg = 0x%x seq_num = 0x%x "
+ "src_proc = 0x%x", (uint)(msg), (msg)->seq_num,
+ (msg)->src_proc);
+ }
+
+exit:
+ if (status < 0)
+ pr_err("messageq_alloc failed! status = 0x%x", status);
+ return msg;
+}
+EXPORT_SYMBOL(messageq_alloc);
+
+/* Frees the message. */
+int messageq_free(messageq_msg msg)
+{
+ u32 status = 0;
+ void *heap = NULL;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(
+ &(messageq_module->ref_count),
+ MESSAGEQ_MAKE_MAGICSTAMP(0),
+ MESSAGEQ_MAKE_MAGICSTAMP(1)) == true))) {
+ status = -ENODEV;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(msg == NULL))) {
+ status = -EINVAL;
+ goto exit;
+ }
+ if (unlikely(msg->heap_id == MESSAGEQ_STATICMSG)) {
+ status = MESSAGEQ_E_CANNOTFREESTATICMSG;
+ goto exit;
+ }
+ if (unlikely(msg->heap_id >= messageq_module->num_heaps)) {
+ status = MESSAGEQ_E_INVALIDHEAPID;
+ goto exit;
+ }
+ if (unlikely(messageq_module->heaps[msg->heap_id] == NULL)) {
+ status = MESSAGEQ_E_INVALIDHEAPID;
+ goto exit;
+ }
+
+ if (unlikely((messageq_module->cfg.trace_flag == true) || \
+ (((*msg).flags & MESSAGEQ_TRACEMASK) != 0))) {
+ pr_info("messageq_free: msg = 0x%x seq_num = 0x%x "
+ "src_proc = 0x%x", (uint)(msg), (msg)->seq_num,
+ (msg)->src_proc);
+ }
+ heap = messageq_module->heaps[msg->heap_id];
+ sl_heap_free(heap, msg, msg->msg_size);
+
+exit:
+ if (status < 0)
+ pr_err("messageq_free failed! status = 0x%x\n", status);
+ return status;
+}
+EXPORT_SYMBOL(messageq_free);
+
+/* Put a message in the queue */
+int messageq_put(u32 queue_id, messageq_msg msg)
+{
+ int status = 0;
+ u16 dst_proc_id = (u16)(queue_id >> 16);
+ struct messageq_object *obj = NULL;
+ void *transport = NULL;
+ u32 priority;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(
+ &(messageq_module->ref_count),
+ MESSAGEQ_MAKE_MAGICSTAMP(0),
+ MESSAGEQ_MAKE_MAGICSTAMP(1)) == true))) {
+ status = -ENODEV;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(queue_id == MESSAGEQ_INVALIDMESSAGEQ))) {
+ status = -EINVAL;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(msg == NULL))) {
+ status = -EINVAL;
+ goto exit;
+ }
+
+ msg->dst_id = (u16)(queue_id);
+ msg->dst_proc = (u16)(queue_id >> 16);
+ if (likely(dst_proc_id != multiproc_self())) {
+ if (unlikely(dst_proc_id >= multiproc_get_num_processors())) {
+ /* Invalid destination processor id */
+ status = MESSAGEQ_E_INVALIDPROCID;
+ goto exit;
+ }
+
+ priority = (u32)((msg->flags) & MESSAGEQ_TRANSPORTPRIORITYMASK);
+ /* Call the transport associated with this message queue */
+ transport = messageq_module->transports[dst_proc_id][priority];
+ if (transport == NULL) {
+ /* Try the other transport */
+ priority = !priority;
+ transport =
+ messageq_module->transports[dst_proc_id][priority];
+ }
+
+ if (unlikely(transport == NULL)) {
+ status = -ENODEV;
+ goto exit;
+ }
+ status = transportshm_put(transport, msg);
+ if (unlikely(status < 0))
+ goto exit;
+ } else {
+ /* It is a local MessageQ */
+ obj = (struct messageq_object *)
+ (messageq_module->queues[(u16)(queue_id)]);
+ /* Check for MessageQ Validity. */
+ if (obj == NULL) {
+ status = MESSAGEQ_E_INVALIDMSG;
+ goto exit;
+ }
+ status = mutex_lock_interruptible(messageq_module->gate_handle);
+ if (status < 0)
+ goto exit;
+ if ((msg->flags & MESSAGEQ_PRIORITYMASK) == \
+ MESSAGEQ_URGENTPRI) {
+ list_add((struct list_head *) msg, &obj->high_list);
+ } else {
+ if ((msg->flags & MESSAGEQ_PRIORITYMASK) == \
+ MESSAGEQ_NORMALPRI) {
+ list_add_tail((struct list_head *) msg,
+ &obj->normal_list);
+ } else {
+ list_add_tail((struct list_head *) msg,
+ &obj->high_list);
+ }
+ }
+ mutex_unlock(messageq_module->gate_handle);
+
+ /* Notify the reader. */
+ if (obj->synchronizer != NULL) {
+ up(obj->synchronizer);
+ /*OsalSemaphore_post(obj->synchronizer);*/
+ }
+ }
+ if (unlikely((messageq_module->cfg.trace_flag == true) || \
+ (((*msg).flags & MESSAGEQ_TRACEMASK) != 0))) {
+ pr_info("messageq_put: msg = 0x%x seq_num = 0x%x "
+ "src_proc = 0x%x dst_proc_id = 0x%x\n", (uint)(msg),
+ (msg)->seq_num, (msg)->src_proc, (msg)->dst_proc);
+ }
+
+exit:
+ if (status < 0)
+ pr_err("messageq_put failed! status = 0x%x\n", status);
+ return status;
+}
+EXPORT_SYMBOL(messageq_put);
+
+/* Register a heap */
+int messageq_register_heap(void *heap_handle, u16 heap_id)
+{
+ int status = 0;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(
+ &(messageq_module->ref_count),
+ MESSAGEQ_MAKE_MAGICSTAMP(0),
+ MESSAGEQ_MAKE_MAGICSTAMP(1)) == true))) {
+ status = -ENODEV;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(heap_handle == NULL))) {
+ /*! @retval -EINVAL Invalid heap_id */
+ status = -EINVAL;
+ goto exit;
+ }
+ /* Make sure the heap_id is valid */
+ if (WARN_ON(unlikely(heap_id >= messageq_module->num_heaps))) {
+ /*! @retval -EINVAL Invalid heap_id */
+ status = -EINVAL;
+ goto exit;
+ }
+
+ status = mutex_lock_interruptible(messageq_module->gate_handle);
+ if (status)
+ goto exit;
+ if (messageq_module->heaps[heap_id] == NULL)
+ messageq_module->heaps[heap_id] = heap_handle;
+ else {
+ /*! @retval MESSAGEQ_E_ALREADYEXISTS Specified heap is
+ already registered. */
+ status = MESSAGEQ_E_ALREADYEXISTS;
+ }
+ mutex_unlock(messageq_module->gate_handle);
+
+exit:
+ if (status < 0) {
+ pr_err("messageq_register_heap failed! "
+ "status = 0x%x\n", status);
+ }
+ return status;
+}
+EXPORT_SYMBOL(messageq_register_heap);
+
+/* Unregister a heap */
+int messageq_unregister_heap(u16 heap_id)
+{
+ int status = 0;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(
+ &(messageq_module->ref_count),
+ MESSAGEQ_MAKE_MAGICSTAMP(0),
+ MESSAGEQ_MAKE_MAGICSTAMP(1)) == true))) {
+ status = -ENODEV;
+ goto exit;
+ }
+ /* Make sure the heap_id is valid */
+ if (WARN_ON(unlikely(heap_id >= messageq_module->num_heaps))) {
+ /*! @retval -EINVAL Invalid heap_id */
+ status = -EINVAL;
+ goto exit;
+ }
+
+ status = mutex_lock_interruptible(messageq_module->gate_handle);
+ if (status)
+ goto exit;
+ if (messageq_module->heaps != NULL)
+ messageq_module->heaps[heap_id] = NULL;
+ mutex_unlock(messageq_module->gate_handle);
+
+exit:
+ if (status < 0) {
+ pr_err("messageq_unregister_heap failed! "
+ "status = 0x%x\n", status);
+ }
+ return status;
+}
+EXPORT_SYMBOL(messageq_unregister_heap);
+
+/* Unblock messageq to prevent waiting forever */
+int messageq_unblock(void *messageq_handle)
+{
+ int status = 0;
+ struct messageq_object *obj = (struct messageq_object *)messageq_handle;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(
+ &(messageq_module->ref_count),
+ MESSAGEQ_MAKE_MAGICSTAMP(0),
+ MESSAGEQ_MAKE_MAGICSTAMP(1)) == true))) {
+ status = -ENODEV;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(obj == NULL)) || (WARN_ON(unlikely(
+ obj->synchronizer == NULL)))) {
+ status = -EINVAL;
+ goto exit;
+ }
+ /* Set instance to 'unblocked' state */
+ obj->unblocked = true;
+ up(obj->synchronizer);
+
+exit:
+ if (status < 0) {
+ pr_err("messageq_unblock failed! status = 0x%x\n",
+ status);
+ }
+ return status;
+}
+
+/* Register a transport */
+int messageq_register_transport(void *messageq_transportshm_handle,
+ u16 proc_id, u32 priority)
+{
+ int status = 0;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(
+ &(messageq_module->ref_count),
+ MESSAGEQ_MAKE_MAGICSTAMP(0),
+ MESSAGEQ_MAKE_MAGICSTAMP(1)) == true))) {
+ status = -ENODEV;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(messageq_transportshm_handle == NULL))) {
+ status = -EINVAL;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(proc_id >= multiproc_get_num_processors()))) {
+ status = -EINVAL;
+ goto exit;
+ }
+
+ status = mutex_lock_interruptible(messageq_module->gate_handle);
+ if (status)
+ goto exit;
+ if (messageq_module->transports[proc_id][priority] == NULL) {
+ messageq_module->transports[proc_id][priority] = \
+ messageq_transportshm_handle;
+ } else {
+ /*! @retval MESSAGEQ_E_ALREADYEXISTS Specified transport is
+ already registered. */
+ status = MESSAGEQ_E_ALREADYEXISTS;
+ }
+ mutex_unlock(messageq_module->gate_handle);
+
+exit:
+ if (status < 0) {
+ pr_err("messageq_register_transport failed! "
+ "status = 0x%x\n", status);
+ }
+ return status;
+}
+EXPORT_SYMBOL(messageq_register_transport);
+
+/* Unregister a transport */
+void messageq_unregister_transport(u16 proc_id, u32 priority)
+{
+ int status = 0;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(
+ &(messageq_module->ref_count),
+ MESSAGEQ_MAKE_MAGICSTAMP(0),
+ MESSAGEQ_MAKE_MAGICSTAMP(1)) == true))) {
+ status = -ENODEV;
+ goto exit;
+ }
+ if (WARN_ON(proc_id >= multiproc_get_num_processors())) {
+ /*! @retval MESSAGEQ_E_PROCIDINVALID Invalid proc_id */
+ status = -EINVAL;
+ goto exit;
+ }
+
+ status = mutex_lock_interruptible(messageq_module->gate_handle);
+ if (status)
+ goto exit;
+ if (messageq_module->transports[proc_id][priority] != NULL)
+ messageq_module->transports[proc_id][priority] = NULL;
+ mutex_unlock(messageq_module->gate_handle);
+
+exit:
+ if (status < 0) {
+ pr_err("messageq_unregister_transport failed! "
+ "status = 0x%x\n", status);
+ }
+ return;
+}
+EXPORT_SYMBOL(messageq_unregister_transport);
+
+/* Set the destination queue of the message. */
+void messageq_set_reply_queue(void *messageq_handle, messageq_msg msg)
+{
+ s32 status = 0;
+
+ struct messageq_object *obj = \
+ (struct messageq_object *) messageq_handle;
+
+ if (WARN_ON(unlikely(messageq_handle == NULL))) {
+ status = -EINVAL;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(msg == NULL))) {
+ status = -EINVAL;
+ goto exit;
+ }
+
+ msg->reply_id = (u16)(obj->queue);
+ msg->reply_proc = (u16)(obj->queue >> 16);
+ return;
+
+exit:
+ pr_err("messageq_set_reply_queue failed: status = 0x%x", status);
+ return;
+}
+EXPORT_SYMBOL(messageq_set_reply_queue);
+
+/* Get the queue _id of the message. */
+u32 messageq_get_queue_id(void *messageq_handle)
+{
+ struct messageq_object *obj = \
+ (struct messageq_object *) messageq_handle;
+ u32 queue_id = MESSAGEQ_INVALIDMESSAGEQ;
+
+ if (WARN_ON(unlikely(obj == NULL))) {
+ pr_err("messageq_get_queue_id: obj passed is NULL!\n");
+ goto exit;
+ }
+
+ queue_id = (obj->queue);
+
+exit:
+ return queue_id;
+}
+EXPORT_SYMBOL(messageq_get_queue_id);
+
+/* Get the proc _id of the message. */
+u16 messageq_get_proc_id(void *messageq_handle)
+{
+ struct messageq_object *obj = \
+ (struct messageq_object *) messageq_handle;
+ u16 proc_id = MULTIPROC_INVALIDID;
+
+ if (WARN_ON(unlikely(obj == NULL))) {
+ pr_err("messageq_get_proc_id: obj passed is NULL!\n");
+ goto exit;
+ }
+
+ proc_id = (u16)(obj->queue >> 16);
+
+exit:
+ return proc_id;
+}
+EXPORT_SYMBOL(messageq_get_proc_id);
+
+/* Get the destination queue of the message. */
+u32 messageq_get_dst_queue(messageq_msg msg)
+{
+ u32 queue_id = MESSAGEQ_INVALIDMESSAGEQ;
+
+ if (WARN_ON(unlikely(msg == NULL))) {
+ pr_err("messageq_get_dst_queue: msg passed is NULL!\n");
+ goto exit;
+ }
+
+ /*construct queue value */
+ if (msg->dst_id != (u32)MESSAGEQ_INVALIDMESSAGEQ)
+ queue_id = ((u32) multiproc_self() << 16) | msg->dst_id;
+
+exit:
+ return queue_id;
+}
+EXPORT_SYMBOL(messageq_get_dst_queue);
+
+/* Get the message id of the message. */
+u16 messageq_get_msg_id(messageq_msg msg)
+{
+ u16 id = MESSAGEQ_INVALIDMSGID;
+
+ if (WARN_ON(unlikely(msg == NULL))) {
+ pr_err("messageq_get_msg_id: msg passed is NULL!\n");
+ goto exit;
+ }
+
+ id = msg->msg_id;
+
+exit:
+ return id;
+}
+EXPORT_SYMBOL(messageq_get_msg_id);
+
+/* Get the message size of the message. */
+u32 messageq_get_msg_size(messageq_msg msg)
+{
+ u32 size = 0;
+
+ if (WARN_ON(unlikely(msg == NULL))) {
+ pr_err("messageq_get_msg_size: msg passed is NULL!\n");
+ goto exit;
+ }
+
+ size = msg->msg_size;
+
+exit:
+ return size;
+}
+EXPORT_SYMBOL(messageq_get_msg_size);
+
+/* Get the message priority of the message. */
+u32 messageq_get_msg_pri(messageq_msg msg)
+{
+ u32 priority = MESSAGEQ_NORMALPRI;
+
+ if (WARN_ON(unlikely(msg == NULL))) {
+ pr_err("messageq_get_msg_pri: msg passed is NULL!\n");
+ goto exit;
+ }
+
+ priority = ((u32)(msg->flags & MESSAGEQ_PRIORITYMASK));
+
+exit:
+ return priority;
+}
+EXPORT_SYMBOL(messageq_get_msg_pri);
+
+/* Get the embedded source message queue out of the message. */
+u32 messageq_get_reply_queue(messageq_msg msg)
+{
+ u32 queue = MESSAGEQ_INVALIDMESSAGEQ;
+
+ if (WARN_ON(unlikely(msg == NULL))) {
+ pr_err("messageq_get_reply_queue: msg passed is NULL!\n");
+ goto exit;
+ }
+
+ if (msg->reply_id != (u16)MESSAGEQ_INVALIDMESSAGEQ)
+ queue = ((u32)(msg->reply_proc) << 16) | msg->reply_id;
+
+exit:
+ return queue;
+}
+EXPORT_SYMBOL(messageq_get_reply_queue);
+
+/* Set the message id of the message. */
+void messageq_set_msg_id(messageq_msg msg, u16 msg_id)
+{
+ if (WARN_ON(unlikely(msg == NULL))) {
+ pr_err("messageq_set_msg_id: msg passed is NULL!\n");
+ goto exit;
+ }
+
+ msg->msg_id = msg_id;
+
+exit:
+ return;
+}
+EXPORT_SYMBOL(messageq_set_msg_id);
+
+/* Set the priority of the message. */
+void messageq_set_msg_pri(messageq_msg msg, u32 priority)
+{
+ if (WARN_ON(unlikely(msg == NULL))) {
+ pr_err("messageq_set_msg_pri: msg passed is NULL!\n");
+ goto exit;
+ }
+
+ msg->flags = priority & MESSAGEQ_PRIORITYMASK;
+
+exit:
+ return;
+}
+EXPORT_SYMBOL(messageq_set_msg_pri);
+
+/* Sets the tracing of a message */
+void messageq_set_msg_trace(messageq_msg msg, bool trace_flag)
+{
+ if (WARN_ON(unlikely(msg == NULL))) {
+ pr_err("messageq_set_msg_trace: msg passed is NULL!\n");
+ goto exit;
+ }
+
+ msg->flags = (msg->flags & ~MESSAGEQ_TRACEMASK) | \
+ (trace_flag << MESSAGEQ_TRACESHIFT);
+
+ pr_info("messageq_set_msg_trace: msg = 0x%x, seq_num = 0x%x"
+ "src_proc = 0x%x trace_flag = 0x%x", (uint)msg,
+ msg->seq_num, msg->src_proc, trace_flag);
+exit:
+ return;
+}
+
+/* Returns the amount of shared memory used by one transport instance.
+ *
+ * The MessageQ module itself does not use any shared memory but the
+ * underlying transport may use some shared memory.
+ */
+uint messageq_shared_mem_req(void *shared_addr)
+{
+ uint mem_req;
+
+ if (likely(multiproc_get_num_processors() > 1)) {
+ /* Determine device-specific shared memory requirements */
+ mem_req = messageq_setup_transport_proxy_shared_mem_req(
+ shared_addr);
+ } else {
+ /* Only 1 processor: no shared memory needed */
+ mem_req = 0;
+ }
+
+ return mem_req;
+}
+EXPORT_SYMBOL(messageq_shared_mem_req);
+
+/* Calls the SetupProxy to setup the MessageQ transports. */
+int messageq_attach(u16 remote_proc_id, void *shared_addr)
+{
+ int status = MESSAGEQ_S_SUCCESS;
+
+ if (likely(multiproc_get_num_processors() > 1)) {
+ /* Use the messageq_setup_transport_proxy to attach
+ * transports */
+ status = messageq_setup_transport_proxy_attach(
+ remote_proc_id, shared_addr);
+ if (status < 0) {
+ pr_err("messageq_attach failed in transport"
+ "setup, status = 0x%x", status);
+ }
+ }
+
+ /*! @retval MESSAGEQ_S_SUCCESS Operation successfully completed! */
+ return status;
+}
+EXPORT_SYMBOL(messageq_attach);
+
+/* Calls the SetupProxy to detach the MessageQ transports. */
+int messageq_detach(u16 remote_proc_id)
+{
+ int status = MESSAGEQ_S_SUCCESS;
+
+ if (likely(multiproc_get_num_processors() > 1)) {
+ /* Use the messageq_setup_transport_proxy to detach
+ * transports */
+ status = messageq_setup_transport_proxy_detach(remote_proc_id);
+ if (unlikely(status < 0)) {
+ pr_err("messageq_detach failed in transport"
+ "detach, status = 0x%x", status);
+ }
+ }
+
+ /*! @retval MESSAGEQ_S_SUCCESS Operation successfully completed! */
+ return status;
+}
+EXPORT_SYMBOL(messageq_detach);
+
+/* =============================================================================
+ * Internal functions
+ * =============================================================================
+ */
+/* Grow the MessageQ table */
+static u16 _messageq_grow(struct messageq_object *obj)
+{
+ u16 queue_index = messageq_module->num_queues;
+ int old_size;
+ void **queues;
+ void **oldqueues;
+
+ /* No parameter validation required since this is an internal func. */
+ old_size = (messageq_module->num_queues) * \
+ sizeof(struct messageq_object *);
+ queues = kmalloc(old_size + sizeof(struct messageq_object *),
+ GFP_KERNEL);
+ if (queues == NULL) {
+ pr_err("_messageq_grow: Growing the messageq failed!\n");
+ goto exit;
+ }
+
+ /* Copy contents into new table */
+ memcpy(queues, messageq_module->queues, old_size);
+ /* Fill in the new entry */
+ queues[queue_index] = (void *)obj;
+ /* Hook-up new table */
+ oldqueues = messageq_module->queues;
+ messageq_module->queues = queues;
+ messageq_module->num_queues++;
+
+ /* Delete old table if not statically defined*/
+ if (messageq_module->can_free_queues == true)
+ kfree(oldqueues);
+ else
+ messageq_module->can_free_queues = true;
+
+exit:
+ return queue_index;
+}
+
+/* This is a helper function to initialize a message. */
+static void messageq_msg_init(messageq_msg msg)
+{
+ s32 status = 0;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(
+ &(messageq_module->ref_count),
+ MESSAGEQ_MAKE_MAGICSTAMP(0),
+ MESSAGEQ_MAKE_MAGICSTAMP(1)) == true))) {
+ status = -ENODEV;
+ goto exit;
+ }
+
+ if (WARN_ON(unlikely(msg == NULL))) {
+ status = -EINVAL;
+ goto exit;
+ }
+
+ msg->reply_id = (u16) MESSAGEQ_INVALIDMESSAGEQ;
+ msg->msg_id = MESSAGEQ_INVALIDMSGID;
+ msg->dst_id = (u16) MESSAGEQ_INVALIDMESSAGEQ;
+ msg->flags = MESSAGEQ_HEADERVERSION | MESSAGEQ_NORMALPRI;
+ msg->src_proc = multiproc_self();
+
+ status = mutex_lock_interruptible(messageq_module->gate_handle);
+ if (status < 0)
+ goto exit;
+ msg->seq_num = messageq_module->seq_num++;
+ mutex_unlock(messageq_module->gate_handle);
+
+exit:
+ if (status < 0)
+ pr_err("messageq_msg_init: Invalid NULL msg specified!\n");
+ return;
+}