diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-06-08 11:31:16 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-06-08 11:31:16 -0700 |
commit | 3f17ea6dea8ba5668873afa54628a91aaa3fb1c0 (patch) | |
tree | afbeb2accd4c2199ddd705ae943995b143a0af02 /sound/soc/intel/sst-baytrail-ipc.c | |
parent | 1860e379875dfe7271c649058aeddffe5afd9d0d (diff) | |
parent | 1a5700bc2d10cd379a795fd2bb377a190af5acd4 (diff) |
Merge branch 'next' (accumulated 3.16 merge window patches) into master
Now that 3.15 is released, this merges the 'next' branch into 'master',
bringing us to the normal situation where my 'master' branch is the
merge window.
* accumulated work in next: (6809 commits)
ufs: sb mutex merge + mutex_destroy
powerpc: update comments for generic idle conversion
cris: update comments for generic idle conversion
idle: remove cpu_idle() forward declarations
nbd: zero from and len fields in NBD_CMD_DISCONNECT.
mm: convert some level-less printks to pr_*
MAINTAINERS: adi-buildroot-devel is moderated
MAINTAINERS: add linux-api for review of API/ABI changes
mm/kmemleak-test.c: use pr_fmt for logging
fs/dlm/debug_fs.c: replace seq_printf by seq_puts
fs/dlm/lockspace.c: convert simple_str to kstr
fs/dlm/config.c: convert simple_str to kstr
mm: mark remap_file_pages() syscall as deprecated
mm: memcontrol: remove unnecessary memcg argument from soft limit functions
mm: memcontrol: clean up memcg zoneinfo lookup
mm/memblock.c: call kmemleak directly from memblock_(alloc|free)
mm/mempool.c: update the kmemleak stack trace for mempool allocations
lib/radix-tree.c: update the kmemleak stack trace for radix tree allocations
mm: introduce kmemleak_update_trace()
mm/kmemleak.c: use %u to print ->checksum
...
Diffstat (limited to 'sound/soc/intel/sst-baytrail-ipc.c')
-rw-r--r-- | sound/soc/intel/sst-baytrail-ipc.c | 132 |
1 files changed, 109 insertions, 23 deletions
diff --git a/sound/soc/intel/sst-baytrail-ipc.c b/sound/soc/intel/sst-baytrail-ipc.c index 0d31dbbf4806..d207b22ea330 100644 --- a/sound/soc/intel/sst-baytrail-ipc.c +++ b/sound/soc/intel/sst-baytrail-ipc.c @@ -22,7 +22,6 @@ #include <linux/export.h> #include <linux/slab.h> #include <linux/delay.h> -#include <linux/list.h> #include <linux/platform_device.h> #include <linux/kthread.h> #include <linux/firmware.h> @@ -173,6 +172,7 @@ struct sst_byt { /* boot */ wait_queue_head_t boot_wait; bool boot_complete; + struct sst_fw *fw; /* IPC messaging */ struct list_head tx_list; @@ -299,6 +299,24 @@ static inline void sst_byt_tx_msg_reply_complete(struct sst_byt *byt, wake_up(&msg->waitq); } +static void sst_byt_drop_all(struct sst_byt *byt) +{ + struct ipc_message *msg, *tmp; + unsigned long flags; + + /* drop all TX and Rx messages before we stall + reset DSP */ + spin_lock_irqsave(&byt->dsp->spinlock, flags); + list_for_each_entry_safe(msg, tmp, &byt->tx_list, list) { + list_move(&msg->list, &byt->empty_list); + } + + list_for_each_entry_safe(msg, tmp, &byt->rx_list, list) { + list_move(&msg->list, &byt->empty_list); + } + + spin_unlock_irqrestore(&byt->dsp->spinlock, flags); +} + static int sst_byt_tx_wait_done(struct sst_byt *byt, struct ipc_message *msg, void *rx_data) { @@ -661,36 +679,33 @@ out: static int sst_byt_stream_operations(struct sst_byt *byt, int type, int stream_id, int wait) { - struct sst_byt_start_stream_params start_stream; u64 header; - void *tx_msg = NULL; - size_t size = 0; - - if (type != IPC_IA_START_STREAM) { - header = sst_byt_header(type, 0, false, stream_id); - } else { - start_stream.byte_offset = 0; - header = sst_byt_header(IPC_IA_START_STREAM, - sizeof(start_stream) + sizeof(u32), - true, stream_id); - tx_msg = &start_stream; - size = sizeof(start_stream); - } + header = sst_byt_header(type, 0, false, stream_id); if (wait) - return sst_byt_ipc_tx_msg_wait(byt, header, - tx_msg, size, NULL, 0); + return sst_byt_ipc_tx_msg_wait(byt, header, NULL, 0, NULL, 0); else - return sst_byt_ipc_tx_msg_nowait(byt, header, tx_msg, size); + return sst_byt_ipc_tx_msg_nowait(byt, header, NULL, 0); } /* stream ALSA trigger operations */ -int sst_byt_stream_start(struct sst_byt *byt, struct sst_byt_stream *stream) +int sst_byt_stream_start(struct sst_byt *byt, struct sst_byt_stream *stream, + u32 start_offset) { + struct sst_byt_start_stream_params start_stream; + void *tx_msg; + size_t size; + u64 header; int ret; - ret = sst_byt_stream_operations(byt, IPC_IA_START_STREAM, - stream->str_id, 0); + start_stream.byte_offset = start_offset; + header = sst_byt_header(IPC_IA_START_STREAM, + sizeof(start_stream) + sizeof(u32), + true, stream->str_id); + tx_msg = &start_stream; + size = sizeof(start_stream); + + ret = sst_byt_ipc_tx_msg_nowait(byt, header, tx_msg, size); if (ret < 0) dev_err(byt->dev, "ipc: error failed to start stream %d\n", stream->str_id); @@ -782,6 +797,73 @@ static struct sst_dsp_device byt_dev = { .ops = &sst_byt_ops, }; +int sst_byt_dsp_suspend_noirq(struct device *dev, struct sst_pdata *pdata) +{ + struct sst_byt *byt = pdata->dsp; + + dev_dbg(byt->dev, "dsp reset\n"); + sst_dsp_reset(byt->dsp); + sst_byt_drop_all(byt); + dev_dbg(byt->dev, "dsp in reset\n"); + + return 0; +} +EXPORT_SYMBOL_GPL(sst_byt_dsp_suspend_noirq); + +int sst_byt_dsp_suspend_late(struct device *dev, struct sst_pdata *pdata) +{ + struct sst_byt *byt = pdata->dsp; + + dev_dbg(byt->dev, "free all blocks and unload fw\n"); + sst_fw_unload(byt->fw); + + return 0; +} +EXPORT_SYMBOL_GPL(sst_byt_dsp_suspend_late); + +int sst_byt_dsp_boot(struct device *dev, struct sst_pdata *pdata) +{ + struct sst_byt *byt = pdata->dsp; + int ret; + + dev_dbg(byt->dev, "reload dsp fw\n"); + + sst_dsp_reset(byt->dsp); + + ret = sst_fw_reload(byt->fw); + if (ret < 0) { + dev_err(dev, "error: failed to reload firmware\n"); + return ret; + } + + /* wait for DSP boot completion */ + byt->boot_complete = false; + sst_dsp_boot(byt->dsp); + dev_dbg(byt->dev, "dsp booting...\n"); + + return 0; +} +EXPORT_SYMBOL_GPL(sst_byt_dsp_boot); + +int sst_byt_dsp_wait_for_ready(struct device *dev, struct sst_pdata *pdata) +{ + struct sst_byt *byt = pdata->dsp; + int err; + + dev_dbg(byt->dev, "wait for dsp reboot\n"); + + err = wait_event_timeout(byt->boot_wait, byt->boot_complete, + msecs_to_jiffies(IPC_BOOT_MSECS)); + if (err == 0) { + dev_err(byt->dev, "ipc: error DSP boot timeout\n"); + return -EIO; + } + + dev_dbg(byt->dev, "dsp rebooted\n"); + return 0; +} +EXPORT_SYMBOL_GPL(sst_byt_dsp_wait_for_ready); + int sst_byt_dsp_init(struct device *dev, struct sst_pdata *pdata) { struct sst_byt *byt; @@ -809,7 +891,7 @@ int sst_byt_dsp_init(struct device *dev, struct sst_pdata *pdata) /* start the IPC message thread */ init_kthread_worker(&byt->kworker); byt->tx_thread = kthread_run(kthread_worker_fn, - &byt->kworker, + &byt->kworker, "%s", dev_name(byt->dev)); if (IS_ERR(byt->tx_thread)) { err = PTR_ERR(byt->tx_thread); @@ -824,7 +906,7 @@ int sst_byt_dsp_init(struct device *dev, struct sst_pdata *pdata) byt->dsp = sst_dsp_new(dev, &byt_dev, pdata); if (byt->dsp == NULL) { err = -ENODEV; - goto err_free_msg; + goto dsp_err; } /* keep the DSP in reset state for base FW loading */ @@ -848,6 +930,7 @@ int sst_byt_dsp_init(struct device *dev, struct sst_pdata *pdata) } pdata->dsp = byt; + byt->fw = byt_sst_fw; return 0; @@ -856,6 +939,8 @@ boot_err: sst_fw_free(byt_sst_fw); fw_err: sst_dsp_free(byt->dsp); +dsp_err: + kthread_stop(byt->tx_thread); err_free_msg: kfree(byt->msg); @@ -870,6 +955,7 @@ void sst_byt_dsp_free(struct device *dev, struct sst_pdata *pdata) sst_dsp_reset(byt->dsp); sst_fw_free_all(byt->dsp); sst_dsp_free(byt->dsp); + kthread_stop(byt->tx_thread); kfree(byt->msg); } EXPORT_SYMBOL_GPL(sst_byt_dsp_free); |