/* * ======== 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, OUT struct msg_queue **phMsgQueue, u32 msgq_id, u32 max_msgs, bhandle arg) { u32 i; u32 num_allocated = 0; struct msg_queue *msg_q; int status = 0; if (!hmsg_mgr || phMsgQueue == NULL || !hmsg_mgr->msg_free_list) { status = -EFAULT; goto func_end; } *phMsgQueue = NULL; /* Allocate msg_queue object */ msg_q = kzalloc(sizeof(struct msg_queue), GFP_KERNEL); if (!msg_q) { status = -ENOMEM; goto func_end; } lst_init_elem((struct list_head *)msg_q); msg_q->max_msgs = max_msgs; msg_q->hmsg_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 */ msg_q->msg_free_list = kzalloc(sizeof(struct lst_list), GFP_KERNEL); msg_q->msg_used_list = kzalloc(sizeof(struct lst_list), GFP_KERNEL); if (msg_q->msg_free_list == NULL || msg_q->msg_used_list == NULL) status = -ENOMEM; else { INIT_LIST_HEAD(&msg_q->msg_free_list->head); INIT_LIST_HEAD(&msg_q->msg_used_list->head); } /* Create event that will be signalled when a message from * the DSP is available. */ if (DSP_SUCCEEDED(status)) { msg_q->sync_event = kzalloc(sizeof(struct sync_object), GFP_KERNEL); if (msg_q->sync_event) sync_init_event(msg_q->sync_event); else status = -ENOMEM; } /* Create a notification list for message ready notification. */ if (DSP_SUCCEEDED(status)) { msg_q->ntfy_obj = kmalloc(sizeof(struct ntfy_object), GFP_KERNEL); if (msg_q->ntfy_obj) ntfy_init(msg_q->ntfy_obj); else status = -ENOMEM; } /* 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. */ if (DSP_SUCCEEDED(status)) { msg_q->sync_done = kzalloc(sizeof(struct sync_object), GFP_KERNEL); if (msg_q->sync_done) sync_init_event(msg_q->sync_done); else status = -ENOMEM; } if (DSP_SUCCEEDED(status)) { msg_q->sync_done_ack = kzalloc(sizeof(struct sync_object), GFP_KERNEL); if (msg_q->sync_done_ack) sync_init_event(msg_q->sync_done_ack); else status = -ENOMEM; } if (DSP_SUCCEEDED(status)) { /* 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 && DSP_SUCCEEDED(status); i++) { status = add_new_msg(hmsg_mgr->msg_free_list); if (DSP_SUCCEEDED(status)) { num_allocated++; status = add_new_msg(msg_q->msg_free_list); } } if (DSP_FAILED(status)) { /* Stay inside CS to prevent others from taking any * of the newly allocated message frames. */ delete_msg_queue(msg_q, num_allocated); } else { lst_put_tail(hmsg_mgr->queue_list, (struct list_head *)msg_q); *phMsgQueue = msg_q; /* Signal that free frames are now available */ if (!LST_IS_EMPTY(hmsg_mgr->msg_free_list)) sync_set_event(hmsg_mgr->sync_event); } /* Exit critical section */ spin_unlock_bh(&hmsg_mgr->msg_mgr_lock); } else { delete_msg_queue(msg_q, 0); } func_end: 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; }