ASoC: Intel: remove conflicts when load/unload multiple firmware images
[cascardo/linux.git] / sound / soc / intel / sst-haswell-ipc.c
index 3f8c482..6c7052a 100644 (file)
@@ -651,11 +651,11 @@ static void hsw_notification_work(struct work_struct *work)
        }
 
        /* tell DSP that notification has been handled */
-       sst_dsp_shim_update_bits_unlocked(hsw->dsp, SST_IPCD,
+       sst_dsp_shim_update_bits(hsw->dsp, SST_IPCD,
                SST_IPCD_BUSY | SST_IPCD_DONE, SST_IPCD_DONE);
 
        /* unmask busy interrupt */
-       sst_dsp_shim_update_bits_unlocked(hsw->dsp, SST_IMRX, SST_IMRX_BUSY, 0);
+       sst_dsp_shim_update_bits(hsw->dsp, SST_IMRX, SST_IMRX_BUSY, 0);
 }
 
 static struct ipc_message *reply_find_msg(struct sst_hsw *hsw, u32 header)
@@ -1228,6 +1228,11 @@ int sst_hsw_stream_free(struct sst_hsw *hsw, struct sst_hsw_stream *stream)
        struct sst_dsp *sst = hsw->dsp;
        unsigned long flags;
 
+       if (!stream) {
+               dev_warn(hsw->dev, "warning: stream is NULL, no stream to free, ignore it.\n");
+               return 0;
+       }
+
        /* dont free DSP streams that are not commited */
        if (!stream->commited)
                goto out;
@@ -1415,6 +1420,16 @@ int sst_hsw_stream_commit(struct sst_hsw *hsw, struct sst_hsw_stream *stream)
        u32 header;
        int ret;
 
+       if (!stream) {
+               dev_warn(hsw->dev, "warning: stream is NULL, no stream to commit, ignore it.\n");
+               return 0;
+       }
+
+       if (stream->commited) {
+               dev_warn(hsw->dev, "warning: stream is already committed, ignore it.\n");
+               return 0;
+       }
+
        trace_ipc_request("stream alloc", stream->host_id);
 
        header = IPC_GLB_TYPE(IPC_GLB_ALLOCATE_STREAM);
@@ -1519,6 +1534,11 @@ int sst_hsw_stream_pause(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
 {
        int ret;
 
+       if (!stream) {
+               dev_warn(hsw->dev, "warning: stream is NULL, no stream to pause, ignore it.\n");
+               return 0;
+       }
+
        trace_ipc_request("stream pause", stream->reply.stream_hw_id);
 
        ret = sst_hsw_stream_operations(hsw, IPC_STR_PAUSE,
@@ -1535,6 +1555,11 @@ int sst_hsw_stream_resume(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
 {
        int ret;
 
+       if (!stream) {
+               dev_warn(hsw->dev, "warning: stream is NULL, no stream to resume, ignore it.\n");
+               return 0;
+       }
+
        trace_ipc_request("stream resume", stream->reply.stream_hw_id);
 
        ret = sst_hsw_stream_operations(hsw, IPC_STR_RESUME,
@@ -1550,6 +1575,11 @@ int sst_hsw_stream_reset(struct sst_hsw *hsw, struct sst_hsw_stream *stream)
 {
        int ret, tries = 10;
 
+       if (!stream) {
+               dev_warn(hsw->dev, "warning: stream is NULL, no stream to reset, ignore it.\n");
+               return 0;
+       }
+
        /* dont reset streams that are not commited */
        if (!stream->commited)
                return 0;
@@ -1840,6 +1870,7 @@ static void sst_hsw_drop_all(struct sst_hsw *hsw)
 int sst_hsw_dsp_load(struct sst_hsw *hsw)
 {
        struct sst_dsp *dsp = hsw->dsp;
+       struct sst_fw *sst_fw, *t;
        int ret;
 
        dev_dbg(hsw->dev, "loading audio DSP....");
@@ -1856,12 +1887,17 @@ int sst_hsw_dsp_load(struct sst_hsw *hsw)
                return ret;
        }
 
-       ret = sst_fw_reload(hsw->sst_fw);
-       if (ret < 0) {
-               dev_err(hsw->dev, "error: SST FW reload failed\n");
-               sst_dsp_dma_put_channel(dsp);
-               return -ENOMEM;
+       list_for_each_entry_safe_reverse(sst_fw, t, &dsp->fw_list, list) {
+               ret = sst_fw_reload(sst_fw);
+               if (ret < 0) {
+                       dev_err(hsw->dev, "error: SST FW reload failed\n");
+                       sst_dsp_dma_put_channel(dsp);
+                       return -ENOMEM;
+               }
        }
+       ret = sst_block_alloc_scratch(hsw->dsp);
+       if (ret < 0)
+               return -EINVAL;
 
        sst_dsp_dma_put_channel(dsp);
        return 0;
@@ -1917,12 +1953,17 @@ int sst_hsw_dsp_runtime_suspend(struct sst_hsw *hsw)
 
 int sst_hsw_dsp_runtime_sleep(struct sst_hsw *hsw)
 {
-       sst_fw_unload(hsw->sst_fw);
-       sst_block_free_scratch(hsw->dsp);
+       struct sst_fw *sst_fw, *t;
+       struct sst_dsp *dsp = hsw->dsp;
+
+       list_for_each_entry_safe(sst_fw, t, &dsp->fw_list, list) {
+               sst_fw_unload(sst_fw);
+       }
+       sst_block_free_scratch(dsp);
 
        hsw->boot_complete = false;
 
-       sst_dsp_sleep(hsw->dsp);
+       sst_dsp_sleep(dsp);
 
        return 0;
 }
@@ -2051,6 +2092,11 @@ int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata)
                goto fw_err;
        }
 
+       /* allocate scratch mem regions */
+       ret = sst_block_alloc_scratch(hsw->dsp);
+       if (ret < 0)
+               goto boot_err;
+
        /* wait for DSP boot completion */
        sst_dsp_boot(hsw->dsp);
        ret = wait_event_timeout(hsw->boot_wait, hsw->boot_complete,