summaryrefslogtreecommitdiff
path: root/drivers/staging/tidspbridge/core/msg_sm.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/tidspbridge/core/msg_sm.c')
-rw-r--r--drivers/staging/tidspbridge/core/msg_sm.c564
1 files changed, 0 insertions, 564 deletions
diff --git a/drivers/staging/tidspbridge/core/msg_sm.c b/drivers/staging/tidspbridge/core/msg_sm.c
deleted file mode 100644
index 7b517eb827fe..000000000000
--- a/drivers/staging/tidspbridge/core/msg_sm.c
+++ /dev/null
@@ -1,564 +0,0 @@
-/*
- * msg_sm.c
- *
- * DSP-BIOS Bridge driver support functions for TI OMAP processors.
- *
- * Implements upper edge functions for Bridge message module.
- *
- * Copyright (C) 2005-2006 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.
- */
-#include <linux/types.h>
-
-/* ----------------------------------- DSP/BIOS Bridge */
-#include <dspbridge/dbdefs.h>
-
-/* ----------------------------------- OS Adaptation Layer */
-#include <dspbridge/sync.h>
-
-/* ----------------------------------- Platform Manager */
-#include <dspbridge/dev.h>
-
-/* ----------------------------------- Others */
-#include <dspbridge/io_sm.h>
-
-/* ----------------------------------- This */
-#include <_msg_sm.h>
-#include <dspbridge/dspmsg.h>
-
-/* ----------------------------------- Function Prototypes */
-static int add_new_msg(struct list_head *msg_list);
-static void delete_msg_mgr(struct msg_mgr *hmsg_mgr);
-static void delete_msg_queue(struct msg_queue *msg_queue_obj, u32 num_to_dsp);
-static void free_msg_list(struct list_head *msg_list);
-
-/*
- * ======== bridge_msg_create ========
- * Create an object to manage message queues. Only one of these objects
- * can exist per device object.
- */
-int bridge_msg_create(struct msg_mgr **msg_man,
- struct dev_object *hdev_obj,
- msg_onexit msg_callback)
-{
- struct msg_mgr *msg_mgr_obj;
- struct io_mgr *hio_mgr;
- int status = 0;
-
- if (!msg_man || !msg_callback || !hdev_obj)
- return -EFAULT;
-
- dev_get_io_mgr(hdev_obj, &hio_mgr);
- if (!hio_mgr)
- return -EFAULT;
-
- *msg_man = NULL;
- /* Allocate msg_ctrl manager object */
- msg_mgr_obj = kzalloc(sizeof(struct msg_mgr), GFP_KERNEL);
- if (!msg_mgr_obj)
- return -ENOMEM;
-
- msg_mgr_obj->on_exit = msg_callback;
- msg_mgr_obj->iomgr = hio_mgr;
- /* List of MSG_QUEUEs */
- INIT_LIST_HEAD(&msg_mgr_obj->queue_list);
- /*
- * Queues of message frames for messages to the DSP. Message
- * frames will only be added to the free queue when a
- * msg_queue object is created.
- */
- INIT_LIST_HEAD(&msg_mgr_obj->msg_free_list);
- INIT_LIST_HEAD(&msg_mgr_obj->msg_used_list);
- spin_lock_init(&msg_mgr_obj->msg_mgr_lock);
-
- /*
- * Create an event to be used by bridge_msg_put() in waiting
- * for an available free frame from the message manager.
- */
- msg_mgr_obj->sync_event =
- kzalloc(sizeof(struct sync_object), GFP_KERNEL);
- if (!msg_mgr_obj->sync_event) {
- kfree(msg_mgr_obj);
- return -ENOMEM;
- }
- sync_init_event(msg_mgr_obj->sync_event);
-
- *msg_man = msg_mgr_obj;
-
- return status;
-}
-
-/*
- * ======== bridge_msg_create_queue ========
- * Create a msg_queue for sending/receiving messages to/from a node
- * on the DSP.
- */
-int bridge_msg_create_queue(struct msg_mgr *hmsg_mgr, struct msg_queue **msgq,
- u32 msgq_id, u32 max_msgs, void *arg)
-{
- u32 i;
- u32 num_allocated = 0;
- struct msg_queue *msg_q;
- int status = 0;
-
- if (!hmsg_mgr || msgq == NULL)
- return -EFAULT;
-
- *msgq = NULL;
- /* Allocate msg_queue object */
- msg_q = kzalloc(sizeof(struct msg_queue), GFP_KERNEL);
- if (!msg_q)
- return -ENOMEM;
-
- msg_q->max_msgs = max_msgs;
- msg_q->msg_mgr = hmsg_mgr;
- msg_q->arg = arg; /* Node handle */
- msg_q->msgq_id = msgq_id; /* Node env (not valid yet) */
- /* Queues of Message frames for messages from the DSP */
- INIT_LIST_HEAD(&msg_q->msg_free_list);
- INIT_LIST_HEAD(&msg_q->msg_used_list);
-
- /* Create event that will be signalled when a message from
- * the DSP is available. */
- msg_q->sync_event = kzalloc(sizeof(struct sync_object), GFP_KERNEL);
- if (!msg_q->sync_event) {
- status = -ENOMEM;
- goto out_err;
-
- }
- sync_init_event(msg_q->sync_event);
-
- /* Create a notification list for message ready notification. */
- msg_q->ntfy_obj = kmalloc(sizeof(struct ntfy_object), GFP_KERNEL);
- if (!msg_q->ntfy_obj) {
- status = -ENOMEM;
- goto out_err;
- }
- ntfy_init(msg_q->ntfy_obj);
-
- /* Create events that will be used to synchronize cleanup
- * when the object is deleted. sync_done will be set to
- * unblock threads in MSG_Put() or MSG_Get(). sync_done_ack
- * will be set by the unblocked thread to signal that it
- * is unblocked and will no longer reference the object. */
- msg_q->sync_done = kzalloc(sizeof(struct sync_object), GFP_KERNEL);
- if (!msg_q->sync_done) {
- status = -ENOMEM;
- goto out_err;
- }
- sync_init_event(msg_q->sync_done);
-
- msg_q->sync_done_ack = kzalloc(sizeof(struct sync_object), GFP_KERNEL);
- if (!msg_q->sync_done_ack) {
- status = -ENOMEM;
- goto out_err;
- }
- sync_init_event(msg_q->sync_done_ack);
-
- /* Enter critical section */
- spin_lock_bh(&hmsg_mgr->msg_mgr_lock);
- /* Initialize message frames and put in appropriate queues */
- for (i = 0; i < max_msgs && !status; i++) {
- status = add_new_msg(&hmsg_mgr->msg_free_list);
- if (!status) {
- num_allocated++;
- status = add_new_msg(&msg_q->msg_free_list);
- }
- }
- if (status) {
- spin_unlock_bh(&hmsg_mgr->msg_mgr_lock);
- goto out_err;
- }
-
- list_add_tail(&msg_q->list_elem, &hmsg_mgr->queue_list);
- *msgq = msg_q;
- /* Signal that free frames are now available */
- if (!list_empty(&hmsg_mgr->msg_free_list))
- sync_set_event(hmsg_mgr->sync_event);
-
- /* Exit critical section */
- spin_unlock_bh(&hmsg_mgr->msg_mgr_lock);
-
- return 0;
-out_err:
- delete_msg_queue(msg_q, num_allocated);
- return status;
-}
-
-/*
- * ======== bridge_msg_delete ========
- * Delete a msg_ctrl manager allocated in bridge_msg_create().
- */
-void bridge_msg_delete(struct msg_mgr *hmsg_mgr)
-{
- delete_msg_mgr(hmsg_mgr);
-}
-
-/*
- * ======== bridge_msg_delete_queue ========
- * Delete a msg_ctrl queue allocated in bridge_msg_create_queue.
- */
-void bridge_msg_delete_queue(struct msg_queue *msg_queue_obj)
-{
- struct msg_mgr *hmsg_mgr;
- u32 io_msg_pend;
-
- if (!msg_queue_obj || !msg_queue_obj->msg_mgr)
- return;
-
- hmsg_mgr = msg_queue_obj->msg_mgr;
- msg_queue_obj->done = true;
- /* Unblock all threads blocked in MSG_Get() or MSG_Put(). */
- io_msg_pend = msg_queue_obj->io_msg_pend;
- while (io_msg_pend) {
- /* Unblock thread */
- sync_set_event(msg_queue_obj->sync_done);
- /* Wait for acknowledgement */
- sync_wait_on_event(msg_queue_obj->sync_done_ack, SYNC_INFINITE);
- io_msg_pend = msg_queue_obj->io_msg_pend;
- }
- /* Remove message queue from hmsg_mgr->queue_list */
- spin_lock_bh(&hmsg_mgr->msg_mgr_lock);
- list_del(&msg_queue_obj->list_elem);
- /* Free the message queue object */
- delete_msg_queue(msg_queue_obj, msg_queue_obj->max_msgs);
- if (list_empty(&hmsg_mgr->msg_free_list))
- sync_reset_event(hmsg_mgr->sync_event);
- spin_unlock_bh(&hmsg_mgr->msg_mgr_lock);
-}
-
-/*
- * ======== bridge_msg_get ========
- * Get a message from a msg_ctrl queue.
- */
-int bridge_msg_get(struct msg_queue *msg_queue_obj,
- struct dsp_msg *pmsg, u32 utimeout)
-{
- struct msg_frame *msg_frame_obj;
- struct msg_mgr *hmsg_mgr;
- struct sync_object *syncs[2];
- u32 index;
- int status = 0;
-
- if (!msg_queue_obj || pmsg == NULL)
- return -ENOMEM;
-
- hmsg_mgr = msg_queue_obj->msg_mgr;
-
- spin_lock_bh(&hmsg_mgr->msg_mgr_lock);
- /* If a message is already there, get it */
- if (!list_empty(&msg_queue_obj->msg_used_list)) {
- msg_frame_obj = list_first_entry(&msg_queue_obj->msg_used_list,
- struct msg_frame, list_elem);
- list_del(&msg_frame_obj->list_elem);
- *pmsg = msg_frame_obj->msg_data.msg;
- list_add_tail(&msg_frame_obj->list_elem,
- &msg_queue_obj->msg_free_list);
- if (list_empty(&msg_queue_obj->msg_used_list))
- sync_reset_event(msg_queue_obj->sync_event);
- spin_unlock_bh(&hmsg_mgr->msg_mgr_lock);
- return 0;
- }
-
- if (msg_queue_obj->done) {
- spin_unlock_bh(&hmsg_mgr->msg_mgr_lock);
- return -EPERM;
- }
- msg_queue_obj->io_msg_pend++;
- spin_unlock_bh(&hmsg_mgr->msg_mgr_lock);
-
- /*
- * Wait til message is available, timeout, or done. We don't
- * have to schedule the DPC, since the DSP will send messages
- * when they are available.
- */
- syncs[0] = msg_queue_obj->sync_event;
- syncs[1] = msg_queue_obj->sync_done;
- status = sync_wait_on_multiple_events(syncs, 2, utimeout, &index);
-
- spin_lock_bh(&hmsg_mgr->msg_mgr_lock);
- if (msg_queue_obj->done) {
- msg_queue_obj->io_msg_pend--;
- spin_unlock_bh(&hmsg_mgr->msg_mgr_lock);
- /*
- * Signal that we're not going to access msg_queue_obj
- * anymore, so it can be deleted.
- */
- sync_set_event(msg_queue_obj->sync_done_ack);
- return -EPERM;
- }
- if (!status && !list_empty(&msg_queue_obj->msg_used_list)) {
- /* Get msg from used list */
- msg_frame_obj = list_first_entry(&msg_queue_obj->msg_used_list,
- struct msg_frame, list_elem);
- list_del(&msg_frame_obj->list_elem);
- /* Copy message into pmsg and put frame on the free list */
- *pmsg = msg_frame_obj->msg_data.msg;
- list_add_tail(&msg_frame_obj->list_elem,
- &msg_queue_obj->msg_free_list);
- }
- msg_queue_obj->io_msg_pend--;
- /* Reset the event if there are still queued messages */
- if (!list_empty(&msg_queue_obj->msg_used_list))
- sync_set_event(msg_queue_obj->sync_event);
-
- spin_unlock_bh(&hmsg_mgr->msg_mgr_lock);
-
- return status;
-}
-
-/*
- * ======== bridge_msg_put ========
- * Put a message onto a msg_ctrl queue.
- */
-int bridge_msg_put(struct msg_queue *msg_queue_obj,
- const struct dsp_msg *pmsg, u32 utimeout)
-{
- struct msg_frame *msg_frame_obj;
- struct msg_mgr *hmsg_mgr;
- struct sync_object *syncs[2];
- u32 index;
- int status;
-
- if (!msg_queue_obj || !pmsg || !msg_queue_obj->msg_mgr)
- return -EFAULT;
-
- hmsg_mgr = msg_queue_obj->msg_mgr;
-
- spin_lock_bh(&hmsg_mgr->msg_mgr_lock);
-
- /* If a message frame is available, use it */
- if (!list_empty(&hmsg_mgr->msg_free_list)) {
- msg_frame_obj = list_first_entry(&hmsg_mgr->msg_free_list,
- struct msg_frame, list_elem);
- list_del(&msg_frame_obj->list_elem);
- msg_frame_obj->msg_data.msg = *pmsg;
- msg_frame_obj->msg_data.msgq_id =
- msg_queue_obj->msgq_id;
- list_add_tail(&msg_frame_obj->list_elem,
- &hmsg_mgr->msg_used_list);
- hmsg_mgr->msgs_pending++;
-
- if (list_empty(&hmsg_mgr->msg_free_list))
- sync_reset_event(hmsg_mgr->sync_event);
-
- /* Release critical section before scheduling DPC */
- spin_unlock_bh(&hmsg_mgr->msg_mgr_lock);
- /* Schedule a DPC, to do the actual data transfer: */
- iosm_schedule(hmsg_mgr->iomgr);
- return 0;
- }
-
- if (msg_queue_obj->done) {
- spin_unlock_bh(&hmsg_mgr->msg_mgr_lock);
- return -EPERM;
- }
- msg_queue_obj->io_msg_pend++;
-
- spin_unlock_bh(&hmsg_mgr->msg_mgr_lock);
-
- /* Wait til a free message frame is available, timeout, or done */
- syncs[0] = hmsg_mgr->sync_event;
- syncs[1] = msg_queue_obj->sync_done;
- status = sync_wait_on_multiple_events(syncs, 2, utimeout, &index);
- if (status)
- return status;
-
- /* Enter critical section */
- spin_lock_bh(&hmsg_mgr->msg_mgr_lock);
- if (msg_queue_obj->done) {
- msg_queue_obj->io_msg_pend--;
- /* Exit critical section */
- spin_unlock_bh(&hmsg_mgr->msg_mgr_lock);
- /*
- * Signal that we're not going to access msg_queue_obj
- * anymore, so it can be deleted.
- */
- sync_set_event(msg_queue_obj->sync_done_ack);
- return -EPERM;
- }
-
- if (list_empty(&hmsg_mgr->msg_free_list)) {
- spin_unlock_bh(&hmsg_mgr->msg_mgr_lock);
- return -EFAULT;
- }
-
- /* Get msg from free list */
- msg_frame_obj = list_first_entry(&hmsg_mgr->msg_free_list,
- struct msg_frame, list_elem);
- /*
- * Copy message into pmsg and put frame on the
- * used list.
- */
- list_del(&msg_frame_obj->list_elem);
- msg_frame_obj->msg_data.msg = *pmsg;
- msg_frame_obj->msg_data.msgq_id = msg_queue_obj->msgq_id;
- list_add_tail(&msg_frame_obj->list_elem, &hmsg_mgr->msg_used_list);
- hmsg_mgr->msgs_pending++;
- /*
- * Schedule a DPC, to do the actual
- * data transfer.
- */
- iosm_schedule(hmsg_mgr->iomgr);
-
- msg_queue_obj->io_msg_pend--;
- /* Reset event if there are still frames available */
- if (!list_empty(&hmsg_mgr->msg_free_list))
- sync_set_event(hmsg_mgr->sync_event);
-
- /* Exit critical section */
- spin_unlock_bh(&hmsg_mgr->msg_mgr_lock);
-
- return 0;
-}
-
-/*
- * ======== bridge_msg_register_notify ========
- */
-int bridge_msg_register_notify(struct msg_queue *msg_queue_obj,
- u32 event_mask, u32 notify_type,
- struct dsp_notification *hnotification)
-{
- int status = 0;
-
- if (!msg_queue_obj || !hnotification) {
- status = -ENOMEM;
- goto func_end;
- }
-
- if (!(event_mask == DSP_NODEMESSAGEREADY || event_mask == 0)) {
- status = -EPERM;
- goto func_end;
- }
-
- if (notify_type != DSP_SIGNALEVENT) {
- status = -EBADR;
- goto func_end;
- }
-
- if (event_mask)
- status = ntfy_register(msg_queue_obj->ntfy_obj, hnotification,
- event_mask, notify_type);
- else
- status = ntfy_unregister(msg_queue_obj->ntfy_obj,
- hnotification);
-
- if (status == -EINVAL) {
- /* Not registered. Ok, since we couldn't have known. Node
- * notifications are split between node state change handled
- * by NODE, and message ready handled by msg_ctrl. */
- status = 0;
- }
-func_end:
- return status;
-}
-
-/*
- * ======== bridge_msg_set_queue_id ========
- */
-void bridge_msg_set_queue_id(struct msg_queue *msg_queue_obj, u32 msgq_id)
-{
- /*
- * A message queue must be created when a node is allocated,
- * so that node_register_notify() can be called before the node
- * is created. Since we don't know the node environment until the
- * node is created, we need this function to set msg_queue_obj->msgq_id
- * to the node environment, after the node is created.
- */
- if (msg_queue_obj)
- msg_queue_obj->msgq_id = msgq_id;
-}
-
-/*
- * ======== add_new_msg ========
- * Must be called in message manager critical section.
- */
-static int add_new_msg(struct list_head *msg_list)
-{
- struct msg_frame *pmsg;
-
- pmsg = kzalloc(sizeof(struct msg_frame), GFP_ATOMIC);
- if (!pmsg)
- return -ENOMEM;
-
- list_add_tail(&pmsg->list_elem, msg_list);
-
- return 0;
-}
-
-/*
- * ======== delete_msg_mgr ========
- */
-static void delete_msg_mgr(struct msg_mgr *hmsg_mgr)
-{
- if (!hmsg_mgr)
- return;
-
- /* FIXME: free elements from queue_list? */
- free_msg_list(&hmsg_mgr->msg_free_list);
- free_msg_list(&hmsg_mgr->msg_used_list);
- kfree(hmsg_mgr->sync_event);
- kfree(hmsg_mgr);
-}
-
-/*
- * ======== delete_msg_queue ========
- */
-static void delete_msg_queue(struct msg_queue *msg_queue_obj, u32 num_to_dsp)
-{
- struct msg_mgr *hmsg_mgr;
- struct msg_frame *pmsg, *tmp;
- u32 i;
-
- if (!msg_queue_obj || !msg_queue_obj->msg_mgr)
- return;
-
- hmsg_mgr = msg_queue_obj->msg_mgr;
-
- /* Pull off num_to_dsp message frames from Msg manager and free */
- i = 0;
- list_for_each_entry_safe(pmsg, tmp, &hmsg_mgr->msg_free_list,
- list_elem) {
- list_del(&pmsg->list_elem);
- kfree(pmsg);
- if (i++ >= num_to_dsp)
- break;
- }
-
- free_msg_list(&msg_queue_obj->msg_free_list);
- free_msg_list(&msg_queue_obj->msg_used_list);
-
- if (msg_queue_obj->ntfy_obj) {
- ntfy_delete(msg_queue_obj->ntfy_obj);
- kfree(msg_queue_obj->ntfy_obj);
- }
-
- kfree(msg_queue_obj->sync_event);
- kfree(msg_queue_obj->sync_done);
- kfree(msg_queue_obj->sync_done_ack);
-
- kfree(msg_queue_obj);
-}
-
-/*
- * ======== free_msg_list ========
- */
-static void free_msg_list(struct list_head *msg_list)
-{
- struct msg_frame *pmsg, *tmp;
-
- if (!msg_list)
- return;
-
- list_for_each_entry_safe(pmsg, tmp, msg_list, list_elem) {
- list_del(&pmsg->list_elem);
- kfree(pmsg);
- }
-}