Audio: Synchronous message posting for ALSA trigger commands
authorNamarta Kohli <namartax.kohli@intel.com>
Wed, 9 May 2012 09:45:32 +0000 (15:15 +0530)
committerbuildbot <buildbot@intel.com>
Mon, 21 May 2012 10:56:19 +0000 (03:56 -0700)
BZ: 34971

In SST driver, whenever ALSA trigger commands are received from alsa framework,
driver schedules work queue.  Inside work queue, IPC message to LPE will be
sent.There will few milli seconds (depends on kernel threads) delay between
acknowledging ALSA with trigger command and actual start of operation by LPE.
ALSA expects trigger commands to be handled immediately and hence it is called
atomically.

Modify audio driver to post trigger message synchronously when trigger command
is received.

Change-Id: Ibb638e355bc06fac1923141b868be947238196b2
Signed-off-by: Namarta Kohli <namartax.kohli@intel.com>
Reviewed-on: http://android.intel.com:8080/47948
Reviewed-by: Abdullah, Omair M <omair.m.abdullah@intel.com>
Reviewed-by: Koul, Vinod <vinod.koul@intel.com>
Reviewed-by: Gupta, ArvindX K <arvindx.k.gupta@intel.com>
Reviewed-by: Hibare, PramodX <pramodx.hibare@intel.com>
Tested-by: Hibare, PramodX <pramodx.hibare@intel.com>
Reviewed-by: buildbot <buildbot@intel.com>
Tested-by: buildbot <buildbot@intel.com>
sound/soc/mid-x86/sst/intel_sst_app_interface.c
sound/soc/mid-x86/sst/intel_sst_common.h
sound/soc/mid-x86/sst/intel_sst_drv_interface.c
sound/soc/mid-x86/sst/intel_sst_ipc.c
sound/soc/mid-x86/sst/intel_sst_stream.c
sound/soc/mid-x86/sst/intel_sst_stream_encoded.c

index 55fc412..40e9706 100644 (file)
@@ -258,11 +258,10 @@ static int intel_sst_mmap_play_capture(u32 str_id,
        struct snd_sst_mmap_buff_entry *tmp_buf;
 
        pr_debug("called for str_id %d\n", str_id);
-       retval = sst_validate_strid(str_id);
-       if (retval)
+       stream = get_stream_info(str_id);
+       if (!stream)
                return -EINVAL;
 
-       stream = &sst_drv_ctx->streams[str_id];
        if (stream->mmapped != true)
                return -EIO;
 
@@ -596,10 +595,9 @@ static int intel_sst_read_write(unsigned int str_id, char __user *buf,
        struct iovec iovec;
        unsigned long nr_segs;
 
-       retval = sst_validate_strid(str_id);
-       if (retval)
+       stream = get_stream_info(str_id);
+       if (!stream)
                return -EINVAL;
-       stream = &sst_drv_ctx->streams[str_id];
        if (stream->mmapped == true) {
                pr_warn("user write and stream is mapped\n");
                return -EIO;
@@ -682,10 +680,9 @@ ssize_t intel_sst_aio_write(struct kiocb *kiocb, const struct iovec *iov,
                return -EINVAL;
 
        pr_debug("called for str_id %d\n", str_id);
-       retval = sst_validate_strid(str_id);
-       if (retval)
+       stream = get_stream_info(str_id);
+       if (!stream)
                return -EINVAL;
-       stream = &sst_drv_ctx->streams[str_id];
        if (stream->mmapped == true)
                return -EIO;
        if (stream->status == STREAM_UN_INIT ||
@@ -763,10 +760,9 @@ ssize_t intel_sst_aio_read(struct kiocb *kiocb, const struct iovec *iov,
        }
 
        pr_debug("called for str_id %d\n", str_id);
-       retval = sst_validate_strid(str_id);
-       if (retval)
+       stream = get_stream_info(str_id);
+       if (!stream)
                return -EINVAL;
-       stream = &sst_drv_ctx->streams[str_id];
        if (stream->mmapped == true)
                return -EIO;
        if (stream->status == STREAM_UN_INIT ||
@@ -1249,10 +1245,11 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg)
                        retval = -EINVAL;
                        break;
                }
-               retval = sst_validate_strid(str_id);
-               if (retval)
+               stream = get_stream_info(str_id);
+               if (!stream) {
+                       retval = -EINVAL;
                        break;
-               stream = &sst_drv_ctx->streams[str_id];
+               }
                mutex_lock(&stream->lock);
                if (stream->status == STREAM_INIT &&
                        stream->need_draining != true) {
index 94d1aa4..ee2cdb9 100644 (file)
@@ -492,7 +492,7 @@ int sst_get_vol(struct snd_sst_vol *set_vol);
 int sst_set_vol(struct snd_sst_vol *set_vol);
 int sst_set_mute(struct snd_sst_mute *set_mute);
 
-
+int sst_sync_post_message(struct ipc_post *msg);
 void sst_post_message(struct work_struct *work);
 void sst_process_message(struct work_struct *work);
 void sst_process_reply(struct work_struct *work);
@@ -651,7 +651,12 @@ sst_set_fw_state_locked(struct intel_sst_drv *sst_drv_ctx, int sst_state)
        sst_drv_ctx->sst_state = sst_state;
        mutex_unlock(&sst_drv_ctx->sst_lock);
 }
-
+static inline struct stream_info *get_stream_info(int str_id)
+{
+       if (sst_validate_strid(str_id))
+               return NULL;
+       return &sst_drv_ctx->streams[str_id];
+}
 int register_sst(struct device *);
 int unregister_sst(struct device *);
 #endif /* __INTEL_SST_COMMON_H__ */
index 2123c4a..d983cb4 100644 (file)
@@ -146,10 +146,9 @@ int sst_stalled(void)
 void free_stream_context(unsigned int str_id)
 {
        struct stream_info *stream;
-
-       if (!sst_validate_strid(str_id)) {
+       stream = get_stream_info(str_id);
+       if (stream) {
                /* str_id is valid, so stream is alloacted */
-               stream = &sst_drv_ctx->streams[str_id];
                if (sst_free_stream(str_id))
                        sst_clean_stream(&sst_drv_ctx->streams[str_id]);
                if (stream->ops == STREAM_OPS_PLAYBACK ||
@@ -447,9 +446,9 @@ static int sst_close_pcm_stream(unsigned int str_id)
        struct stream_info *stream;
 
        pr_debug("stream free called\n");
-       if (sst_validate_strid(str_id))
+       stream = get_stream_info(str_id);
+       if (!stream)
                return -EINVAL;
-       stream = &sst_drv_ctx->streams[str_id];
        free_stream_context(str_id);
        stream->pcm_substream = NULL;
        stream->status = STREAM_UN_INIT;
@@ -460,6 +459,16 @@ static int sst_close_pcm_stream(unsigned int str_id)
        return 0;
 }
 
+int sst_send_sync_msg(int ipc, int str_id)
+{
+       struct ipc_post *msg = NULL;
+
+       if (sst_create_short_msg(&msg))
+               return -ENOMEM;
+       sst_fill_header(&msg->header, ipc, 0, str_id);
+       return sst_sync_post_message(msg);
+}
+
 /*
  * sst_device_control - Set Control params
  *
@@ -476,9 +485,7 @@ static int sst_device_control(int cmd, void *arg)
 
        switch (cmd) {
        case SST_SND_PAUSE:
-       case SST_SND_RESUME:
-       case SST_SND_DROP:
-       case SST_SND_START: {
+       case SST_SND_RESUME: {
                struct mad_ops_wq *work = kzalloc(sizeof(*work), GFP_ATOMIC);
                if (!work)
                        return -ENOMEM;
@@ -488,6 +495,32 @@ static int sst_device_control(int cmd, void *arg)
                queue_work(sst_drv_ctx->mad_wq, &work->wq);
                break;
        }
+       case SST_SND_START: {
+               struct stream_info *str_info;
+               int ipc;
+               str_id = *(int *)arg;
+               str_info = get_stream_info(str_id);
+               if (!str_info)
+                       return -EINVAL;
+               ipc = IPC_IA_START_STREAM;
+               str_info->prev = str_info->status;
+               str_info->status = STREAM_RUNNING;
+               retval = sst_send_sync_msg(ipc, str_id);
+               break;
+       }
+       case SST_SND_DROP: {
+               struct stream_info *str_info;
+               int ipc;
+               str_id = *(int *)arg;
+               str_info = get_stream_info(str_id);
+               if (!str_info)
+                       return -EINVAL;
+               ipc = IPC_IA_DROP_STREAM;
+               str_info->prev = STREAM_UN_INIT;
+               str_info->status = STREAM_INIT;
+               retval = sst_send_sync_msg(ipc, str_id);
+               break;
+       }
        case SST_SND_STREAM_INIT: {
                struct pcm_stream_info *str_info;
                struct stream_info *stream;
@@ -495,11 +528,11 @@ static int sst_device_control(int cmd, void *arg)
                pr_debug("stream init called\n");
                str_info = (struct pcm_stream_info *)arg;
                str_id = str_info->str_id;
-               retval = sst_validate_strid(str_id);
-               if (retval)
+               stream = get_stream_info(str_id);
+               if (!stream) {
+                       retval = -EINVAL;
                        break;
-
-               stream = &sst_drv_ctx->streams[str_id];
+               }
                pr_debug("setting the period ptrs\n");
                stream->pcm_substream = str_info->mad_substream;
                stream->period_elapsed = str_info->period_elapsed;
@@ -517,10 +550,11 @@ static int sst_device_control(int cmd, void *arg)
 
                stream_info = (struct pcm_stream_info *)arg;
                str_id = stream_info->str_id;
-               retval = sst_validate_strid(str_id);
-               if (retval)
+               stream = get_stream_info(str_id);
+               if (!stream) {
+                       retval = -EINVAL;
                        break;
-               stream = &sst_drv_ctx->streams[str_id];
+               }
 
                if (!stream->pcm_substream)
                        break;
index 81e4c91..10132fd 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/pci.h>
 #include <linux/firmware.h>
 #include <linux/sched.h>
+#include <linux/delay.h>
 #include <sound/intel_sst_ioctl.h>
 #include "../sst_platform.h"
 #include "intel_sst_fw_ipc.h"
@@ -179,6 +180,44 @@ void sst_post_message(struct work_struct *work)
        kfree(msg);
 }
 
+/* use this for trigger ops to post syncronous msgs
+ */
+int sst_sync_post_message(struct ipc_post *msg)
+{
+       union ipc_header header;
+       unsigned int loop_count = 0;
+       int retval = 0;
+
+       pr_debug("sst: sync post message called\n");
+       spin_lock(&sst_drv_ctx->list_spin_lock);
+
+       /* check busy bit */
+       header.full = sst_shim_read(sst_drv_ctx->shim, SST_IPCX);
+       while (header.part.busy) {
+               if (loop_count > 10) {
+                       pr_err("busy wait failed, cant send this msg\n");
+                       retval = -EBUSY;
+                       goto out;
+               }
+               usleep_range(5000, 5000);
+               loop_count++;
+               header.full = sst_shim_read(sst_drv_ctx->shim, SST_IPCX);
+       };
+       pr_debug("sst: Post message: header = %x\n", msg->header.full);
+       pr_debug("sst: size: = %x\n", msg->header.part.data);
+       if (msg->header.part.large)
+               memcpy_toio(sst_drv_ctx->mailbox + SST_MAILBOX_SEND,
+                       msg->mailbox_data, msg->header.part.data);
+
+       sst_shim_write(sst_drv_ctx->shim, SST_IPCX, msg->header.full);
+
+out:
+       spin_unlock(&sst_drv_ctx->list_spin_lock);
+       kfree(msg->mailbox_data);
+       kfree(msg);
+       return retval;
+}
+
 /*
  * sst_clear_interrupt - clear the SST FW interrupt
  *
@@ -276,12 +315,12 @@ void sst_process_message(struct work_struct *work)
                if (sst_drv_ctx->pci_id == SST_MRST_PCI_ID) {
                        struct stream_info *stream ;
 
-                       if (sst_validate_strid(str_id)) {
+                       stream = get_stream_info(str_id);
+                       if (!stream) {
                                pr_err("strid %d invalid\n", str_id);
                                break;
                        }
                        /* call sst_play_frame */
-                       stream = &sst_drv_ctx->streams[str_id];
                        pr_debug("sst_play_frames for %d\n",
                                        msg->header.part.str_id);
                        mutex_lock(&sst_drv_ctx->streams[str_id].lock);
@@ -295,11 +334,11 @@ void sst_process_message(struct work_struct *work)
                if (sst_drv_ctx->pci_id == SST_MRST_PCI_ID) {
                        struct stream_info *stream;
                        /* call sst_capture_frame */
-                       if (sst_validate_strid(str_id)) {
+                       stream = get_stream_info(str_id);
+                       if (!stream) {
                                pr_err("str id %d invalid\n", str_id);
                                break;
                        }
-                       stream = &sst_drv_ctx->streams[str_id];
                        pr_debug("sst_capture_frames for %d\n",
                                        msg->header.part.str_id);
                        mutex_lock(&stream->lock);
@@ -546,11 +585,11 @@ void sst_process_reply(struct work_struct *work)
                break;
 
        case IPC_IA_GET_STREAM_PARAMS:
-               if (sst_validate_strid(str_id)) {
+               str_info = get_stream_info(str_id);
+               if (!str_info) {
                        pr_err("stream id %d invalid\n", str_id);
                        break;
                }
-               str_info = &sst_drv_ctx->streams[str_id];
                if (msg->header.part.large) {
                        pr_debug("Get stream large success\n");
                        memcpy_fromio(str_info->ctrl_blk.data,
@@ -569,11 +608,11 @@ void sst_process_reply(struct work_struct *work)
                }
                break;
        case IPC_IA_DECODE_FRAMES:
-               if (sst_validate_strid(str_id)) {
+               str_info = get_stream_info(str_id);
+               if (!str_info) {
                        pr_err("stream id %d invalid\n", str_id);
                        break;
                }
-               str_info = &sst_drv_ctx->streams[str_id];
                if (msg->header.part.large) {
                        pr_debug("Msg succeeded %x\n",
                                       msg->header.part.msg_id);
@@ -593,11 +632,11 @@ void sst_process_reply(struct work_struct *work)
                }
                break;
        case IPC_IA_DRAIN_STREAM:
-               if (sst_validate_strid(str_id)) {
+               str_info = get_stream_info(str_id);
+               if (!str_info) {
                        pr_err("stream id %d invalid\n", str_id);
                        break;
                }
-               str_info = &sst_drv_ctx->streams[str_id];
                if (!msg->header.part.data) {
                        pr_debug("Msg succeeded %x\n",
                                        msg->header.part.msg_id);
@@ -618,11 +657,11 @@ void sst_process_reply(struct work_struct *work)
                break;
 
        case IPC_IA_DROP_STREAM:
-               if (sst_validate_strid(str_id)) {
+               str_info = get_stream_info(str_id);
+               if (!str_info) {
                        pr_err("str id %d invalid\n", str_id);
                        break;
                }
-               str_info = &sst_drv_ctx->streams[str_id];
                if (msg->header.part.large) {
                        struct snd_sst_drop_response *drop_resp =
                                (struct snd_sst_drop_response *)msg->mailbox;
@@ -661,7 +700,11 @@ void sst_process_reply(struct work_struct *work)
        case IPC_IA_PAUSE_STREAM:
        case IPC_IA_RESUME_STREAM:
        case IPC_IA_SET_STREAM_PARAMS:
-               str_info = &sst_drv_ctx->streams[str_id];
+               str_info = get_stream_info(str_id);
+               if (!str_info) {
+                       pr_err(" stream id %d invalid\n", str_id);
+                       break;
+               }
                if (!msg->header.part.data) {
                        pr_debug("Msg succeeded %x\n",
                                        msg->header.part.msg_id);
@@ -672,10 +715,6 @@ void sst_process_reply(struct work_struct *work)
                                        msg->header.part.data);
                        str_info->ctrl_blk.ret_code = -msg->header.part.data;
                }
-               if (sst_validate_strid(str_id)) {
-                       pr_err(" stream id %d invalid\n", str_id);
-                       break;
-               }
 
                if (str_info->ctrl_blk.on == true) {
                        str_info->ctrl_blk.on = false;
index 37391f0..66f4bf4 100644 (file)
@@ -349,15 +349,13 @@ int sst_get_fw_info(struct snd_sst_fw_info *info)
 */
 int sst_start_stream(int str_id)
 {
-       int retval = 0;
        struct ipc_post *msg = NULL;
        struct stream_info *str_info;
 
        pr_debug("sst_start_stream for %d\n", str_id);
-       retval = sst_validate_strid(str_id);
-       if (retval)
-               return retval;
-       str_info = &sst_drv_ctx->streams[str_id];
+       str_info = get_stream_info(str_id);
+       if (!str_info)
+               return -EINVAL;
        if (str_info->status != STREAM_INIT)
                return -EBADRQC;
        if (sst_create_short_msg(&msg))
@@ -368,7 +366,7 @@ int sst_start_stream(int str_id)
        list_add_tail(&msg->node, &sst_drv_ctx->ipc_dispatch_list);
        spin_unlock(&sst_drv_ctx->list_spin_lock);
        sst_post_message(&sst_drv_ctx->ipc_post_msg_wq);
-       return retval;
+       return 0;
 }
 
 /*
@@ -385,10 +383,9 @@ int sst_pause_stream(int str_id)
        struct stream_info *str_info;
 
        pr_debug("SST DBG:sst_pause_stream for %d\n", str_id);
-       retval = sst_validate_strid(str_id);
-       if (retval)
-               return retval;
-       str_info = &sst_drv_ctx->streams[str_id];
+       str_info = get_stream_info(str_id);
+       if (!str_info)
+               return -EINVAL;
        if (str_info->status == STREAM_PAUSED)
                return 0;
        if (str_info->status == STREAM_RUNNING ||
@@ -443,10 +440,9 @@ int sst_resume_stream(int str_id)
        struct stream_info *str_info;
 
        pr_debug("SST DBG:sst_resume_stream for %d\n", str_id);
-       retval = sst_validate_strid(str_id);
-       if (retval)
-               return retval;
-       str_info = &sst_drv_ctx->streams[str_id];
+       str_info = get_stream_info(str_id);
+       if (!str_info)
+               return -EINVAL;
        if (str_info->status == STREAM_RUNNING)
                        return 0;
        if (str_info->status == STREAM_PAUSED) {
@@ -504,10 +500,9 @@ int sst_drop_stream(int str_id)
        struct stream_info *str_info;
 
        pr_debug("SST DBG:sst_drop_stream for %d\n", str_id);
-       retval = sst_validate_strid(str_id);
-       if (retval)
-               return retval;
-       str_info = &sst_drv_ctx->streams[str_id];
+       str_info = get_stream_info(str_id);
+       if (!str_info)
+               return -EINVAL;
 
        mutex_lock(&str_info->lock);
        if (str_info->status != STREAM_UN_INIT &&
@@ -562,10 +557,9 @@ int sst_drain_stream(int str_id)
        struct stream_info *str_info;
 
        pr_debug("SST DBG:sst_drain_stream for %d\n", str_id);
-       retval = sst_validate_strid(str_id);
-       if (retval)
-               return retval;
-       str_info = &sst_drv_ctx->streams[str_id];
+       str_info = get_stream_info(str_id);
+       if (!str_info)
+               return -EINVAL;
 
        if (str_info->status != STREAM_RUNNING &&
                str_info->status != STREAM_INIT &&
@@ -609,10 +603,9 @@ int sst_free_stream(int str_id)
        struct stream_info *str_info;
 
        pr_debug("SST DBG:sst_free_stream for %d\n", str_id);
-       retval = sst_validate_strid(str_id);
-       if (retval)
-               return retval;
-       str_info = &sst_drv_ctx->streams[str_id];
+       str_info = get_stream_info(str_id);
+       if (!str_info)
+               return -EINVAL;
 
        mutex_lock(&str_info->lock);
        if (str_info->status != STREAM_UN_INIT) {
index 5ea143f..000872c 100644 (file)
@@ -57,11 +57,10 @@ int sst_get_stream_params(int str_id,
        struct snd_sst_fw_get_stream_params *fw_params;
 
        pr_debug("get_stream for %d\n", str_id);
-       retval = sst_validate_strid(str_id);
-       if (retval)
-               return retval;
+       str_info = get_stream_info(str_id);
+       if (!str_info)
+               return -EINVAL;
 
-       str_info = &sst_drv_ctx->streams[str_id];
        if (str_info->status != STREAM_UN_INIT) {
                if (str_info->ctrl_blk.on == true) {
                        pr_err("control path in use\n");
@@ -130,11 +129,10 @@ int sst_set_stream_param(int str_id, struct sst_stream_params *str_param)
                pr_err("Invalid operation\n");
                return -EINVAL;
        }
-       retval = sst_validate_strid(str_id);
-       if (retval)
-               return retval;
+       str_info = get_stream_info(str_id);
+       if (!str_info)
+               return -EINVAL;
        pr_debug("set_stream for %d\n", str_id);
-       str_info =  &sst_drv_ctx->streams[str_id];
        if (sst_drv_ctx->streams[str_id].status == STREAM_INIT) {
                if (str_info->ctrl_blk.on == true) {
                        pr_err("control path in use\n");
@@ -549,18 +547,16 @@ static int sst_create_sg_list(struct stream_info *stream,
  */
 int sst_play_frame(int str_id)
 {
-       int retval = 0;
        struct ipc_post *msg = NULL;
        struct sst_frame_info sg_list = {0};
        struct sst_stream_bufs *kbufs = NULL, *_kbufs;
        struct stream_info *stream;
 
        pr_debug("play frame for %d\n", str_id);
-       retval = sst_validate_strid(str_id);
-       if (retval)
-               return retval;
+       stream = get_stream_info(str_id);
+       if (!stream)
+               return -EINVAL;
 
-       stream = &sst_drv_ctx->streams[str_id];
        /* clear prev sent buffers */
        list_for_each_entry_safe(kbufs, _kbufs, &stream->bufs, node) {
                if (kbufs->in_use == true) {
@@ -631,7 +627,6 @@ int sst_play_frame(int str_id)
  */
 int sst_capture_frame(int str_id)
 {
-       int retval = 0;
        struct ipc_post *msg = NULL;
        struct sst_frame_info sg_list = {0};
        struct sst_stream_bufs *kbufs = NULL, *_kbufs;
@@ -639,10 +634,9 @@ int sst_capture_frame(int str_id)
 
 
        pr_debug("capture frame for %d\n", str_id);
-       retval = sst_validate_strid(str_id);
-       if (retval)
-               return retval;
-       stream = &sst_drv_ctx->streams[str_id];
+       stream = get_stream_info(str_id);
+       if (!stream)
+               return -EINVAL;
        /* clear prev sent buffers */
        list_for_each_entry_safe(kbufs, _kbufs, &stream->bufs, node) {
                if (kbufs->in_use == true) {
@@ -1033,11 +1027,10 @@ int sst_decode(int str_id, struct snd_sst_dbufs *dbufs)
 
        pr_debug("Powering_down_PMIC...\n");
 
-       retval = sst_validate_strid(str_id);
-       if (retval)
-               return retval;
+       str_info = get_stream_info(str_id);
+       if (!str_info)
+               return -EINVAL;
 
-       str_info = &sst_drv_ctx->streams[str_id];
        if (str_info->status != STREAM_INIT) {
                pr_err("invalid stream state = %d\n",
                               str_info->status);