From ad83ac7e64cf4d396c3f3c59618160ed8f8cce5d Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Mon, 2 Jul 2018 15:30:20 +0100 Subject: [PATCH 1/7] [SQUASHME] ASoC: sof: core: cleanup - add comments and reorder funcs Add comments describing funcs/code blocks and reorder funcs so features are grouped. Signed-off-by: Liam Girdwood --- sound/soc/sof/core.c | 87 +++++++++++++++++++++++++--------------- sound/soc/sof/sof-priv.h | 19 +++++---- 2 files changed, 63 insertions(+), 43 deletions(-) diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index b523496612d5ae..7d633449ac0e5f 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -19,8 +19,13 @@ #include "sof-priv.h" #include "ops.h" -#define TIMEOUT_IPC 5 -#define TIMEOUT_BOOT 100 +/* SOF defaults if not provided by the platform in ms */ +#define TIMEOUT_DEFAULT_IPC 5 +#define TIMEOUT_DEFAULT_BOOT 100 + +/* + * Generic object lookup APIs. + */ struct snd_sof_pcm *snd_sof_find_spcm_dai(struct snd_sof_dev *sdev, struct snd_soc_pcm_runtime *rtd) @@ -122,11 +127,16 @@ static inline unsigned int sof_get_pages(size_t size) return (size + PAGE_SIZE - 1) >> PAGE_SHIFT; } +/* + * FW Panic/fault handling. + */ + struct sof_panic_msg { u32 id; const char *msg; }; +/* standard FW panic types */ static const struct sof_panic_msg panic_msg[] = { {SOF_IPC_PANIC_MEM, "out of memory"}, {SOF_IPC_PANIC_WORK, "work subsystem init failed"}, @@ -177,6 +187,43 @@ int snd_sof_get_status(struct snd_sof_dev *sdev, u32 panic_code, } EXPORT_SYMBOL(snd_sof_get_status); +/* + * Generic buffer page table creation. + */ + +int snd_sof_create_page_table(struct snd_sof_dev *sdev, + struct snd_dma_buffer *dmab, + unsigned char *page_table, size_t size) +{ + int i, pages; + + pages = snd_sgbuf_aligned_pages(size); + + dev_dbg(sdev->dev, "generating page table for %p size 0x%zx pages %d\n", + dmab->area, size, pages); + + for (i = 0; i < pages; i++) { + u32 idx = (((i << 2) + i)) >> 1; + u32 pfn = snd_sgbuf_get_addr(dmab, i * PAGE_SIZE) >> PAGE_SHIFT; + u32 *pg_table; + + dev_dbg(sdev->dev, "pfn i %i idx %d pfn %x\n", i, idx, pfn); + + pg_table = (u32 *)(page_table + idx); + + if (i & 1) + *pg_table |= (pfn << 4); + else + *pg_table |= pfn; + } + + return pages; +} + +/* + * SOF Driver enumeration. + */ + static int sof_probe(struct platform_device *pdev) { struct snd_sof_pdata *plat_data = dev_get_platdata(&pdev->dev); @@ -210,17 +257,17 @@ static int sof_probe(struct platform_device *pdev) spin_lock_init(&sdev->ipc_lock); spin_lock_init(&sdev->hw_lock); - /* set up platform and component drivers */ + /* set up platform component driver */ snd_sof_new_platform_drv(sdev); snd_sof_new_dai_drv(sdev); /* set default timeouts if none provided */ if (plat_data->desc->ipc_timeout == 0) - sdev->ipc_timeout = TIMEOUT_IPC; + sdev->ipc_timeout = TIMEOUT_DEFAULT_IPC; else sdev->ipc_timeout = plat_data->desc->ipc_timeout; if (plat_data->desc->boot_timeout == 0) - sdev->boot_timeout = TIMEOUT_BOOT; + sdev->boot_timeout = TIMEOUT_DEFAULT_BOOT; else sdev->boot_timeout = plat_data->desc->boot_timeout; @@ -279,8 +326,10 @@ static int sof_probe(struct platform_device *pdev) goto comp_err; } + /* init DMA trace */ ret = snd_sof_init_trace(sdev); if (ret < 0) { + /* non fatal */ dev_warn(sdev->dev, "warning: failed to initialize trace %d\n", ret); } @@ -321,34 +370,6 @@ void snd_sof_shutdown(struct device *dev) } EXPORT_SYMBOL(snd_sof_shutdown); -int snd_sof_create_page_table(struct snd_sof_dev *sdev, - struct snd_dma_buffer *dmab, - unsigned char *page_table, size_t size) -{ - int i, pages; - - pages = sof_get_pages(size); - - dev_dbg(sdev->dev, "generating page table for %p size 0x%zx pages %d\n", - dmab->area, size, pages); - - for (i = 0; i < pages; i++) { - u32 idx = (((i << 2) + i)) >> 1; - u32 pfn = snd_sgbuf_get_addr(dmab, i * PAGE_SIZE) >> PAGE_SHIFT; - u32 *pg_table; - - dev_dbg(sdev->dev, "pfn i %i idx %d pfn %x\n", i, idx, pfn); - - pg_table = (u32 *)(page_table + idx); - - if (i & 1) - *pg_table |= (pfn << 4); - else - *pg_table |= pfn; - } - - return pages; -} static struct platform_driver sof_driver = { .driver = { diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index fabfcb25180940..89f71951988169 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -112,21 +112,20 @@ struct snd_sof_dsp_ops { void (*dbg_dump)(struct snd_sof_dev *sof_dev, u32 flags); /* connect pcm substream to a host stream */ - int (*host_stream_open)(struct snd_sof_dev *sdev, - struct snd_pcm_substream *substream); + int (*pcm_open)(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream); /* disconnect pcm substream to a host stream */ - int (*host_stream_close)(struct snd_sof_dev *sdev, - struct snd_pcm_substream *substream); + int (*pcm_close)(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream); /* host stream hw params */ - int (*host_stream_hw_params)(struct snd_sof_dev *sdev, - struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params); + int (*pcm_hw_params)(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params); /* host stream trigger */ - int (*host_stream_trigger)(struct snd_sof_dev *sdev, - struct snd_pcm_substream *substream, - int cmd); + int (*pcm_trigger)(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream, int cmd); /* FW loading */ int (*load_firmware)(struct snd_sof_dev *sof_dev, From 73eb318245f81d76bbf9fed30aec00a8c78c2ce5 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Mon, 2 Jul 2018 15:30:38 +0100 Subject: [PATCH 2/7] [SQUASHME] ASoC: sof: pcm: cleanup - add comments and reorder funcs Add comments describing funcs/code blocks and reorder funcs so features are grouped. Signed-off-by: Liam Girdwood --- sound/soc/sof/pcm.c | 42 +++++++++++++++++++----------------------- 1 file changed, 19 insertions(+), 23 deletions(-) diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index 558d054af826cd..76199046bb9bb8 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -6,6 +6,8 @@ * Copyright(c) 2017 Intel Corporation. All rights reserved. * * Author: Liam Girdwood + * + * PCM Layer, interface between ALSA and IPC. */ #include @@ -25,6 +27,7 @@ #include #include #include "sof-priv.h" +#include "ops.h" /* Create DMA buffer page table for DSP */ static int create_page_table(struct snd_pcm_substream *substream, @@ -49,7 +52,6 @@ static int sof_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_runtime *runtime = substream->runtime; struct snd_sof_dev *sdev = snd_soc_platform_get_drvdata(rtd->platform); - const struct snd_sof_dsp_ops *ops = sdev->ops; struct snd_sof_pcm *spcm = rtd->sof; struct sof_ipc_pcm_params pcm; struct sof_ipc_pcm_params_reply ipc_params_reply; @@ -134,11 +136,11 @@ static int sof_pcm_hw_params(struct snd_pcm_substream *substream, } /* firmware already configured host stream */ - if (ops && ops->host_stream_hw_params) { - pcm.params.stream_tag = - ops->host_stream_hw_params(sdev, substream, params); - dev_dbg(sdev->dev, "stream_tag %d", pcm.params.stream_tag); - } + pcm.params.stream_tag = snd_sof_pcm_platform_hw_params(sdev, + substream, + params); + dev_dbg(sdev->dev, "stream_tag %d", pcm.params.stream_tag); + /* send IPC to the DSP */ ret = sof_ipc_tx_message(sdev->ipc, pcm.hdr.cmd, &pcm, sizeof(pcm), @@ -197,7 +199,6 @@ static int sof_pcm_trigger(struct snd_pcm_substream *substream, int cmd) struct snd_sof_pcm *spcm = rtd->sof; struct sof_ipc_stream stream; struct sof_ipc_reply reply; - const struct snd_sof_dsp_ops *ops = sdev->ops; int ret = 0; /* nothing todo for BE */ @@ -233,8 +234,7 @@ static int sof_pcm_trigger(struct snd_pcm_substream *substream, int cmd) } /* set RUN firstly per the sequence suggested by firmware team */ - if (ops && ops->host_stream_trigger) - ret = ops->host_stream_trigger(sdev, substream, cmd); + snd_sof_pcm_platform_trigger(sdev, substream, cmd); /* send IPC to the DSP */ ret = sof_ipc_tx_message(sdev->ipc, stream.hdr.cmd, &stream, @@ -255,7 +255,7 @@ static snd_pcm_uframes_t sof_pcm_pointer(struct snd_pcm_substream *substream) if (rtd->dai_link->no_pcm) return 0; - /* TODO: call HW position callback */ + /* read position from DSP */ host = bytes_to_frames(substream->runtime, spcm->stream[substream->stream].posn.host_posn); dai = bytes_to_frames(substream->runtime, @@ -276,7 +276,6 @@ static int sof_pcm_open(struct snd_pcm_substream *substream) struct snd_sof_pcm *spcm = rtd->sof; struct snd_soc_tplg_stream_caps *caps = &spcm->pcm.caps[substream->stream]; - const struct snd_sof_dsp_ops *ops = sdev->ops; /* nothing todo for BE */ if (rtd->dai_link->no_pcm) @@ -320,18 +319,14 @@ static int sof_pcm_open(struct snd_pcm_substream *substream) dev_dbg(sdev->dev, "buffer max %zd bytes\n", runtime->hw.buffer_bytes_max); - // TODO: create IPC to get this from DSP pipeline - //runtime->hw.fifo_size = hw->fifo_size; - /* set wait time - TODO: come from topology */ - snd_pcm_wait_time(substream, 500); + substream->wait_time = 500; spcm->stream[substream->stream].posn.host_posn = 0; spcm->stream[substream->stream].posn.dai_posn = 0; spcm->stream[substream->stream].substream = substream; - if (ops && ops->host_stream_open) - ops->host_stream_open(sdev, substream); + snd_sof_pcm_platform_open(sdev, substream); mutex_unlock(&spcm->mutex); return 0; @@ -343,7 +338,6 @@ static int sof_pcm_close(struct snd_pcm_substream *substream) struct snd_sof_dev *sdev = snd_soc_platform_get_drvdata(rtd->platform); struct snd_sof_pcm *spcm = rtd->sof; - const struct snd_sof_dsp_ops *ops = sdev->ops; /* nothing todo for BE */ if (rtd->dai_link->no_pcm) @@ -352,8 +346,7 @@ static int sof_pcm_close(struct snd_pcm_substream *substream) dev_dbg(sdev->dev, "pcm: close stream %d dir %d\n", spcm->pcm.pcm_id, substream->stream); - if (ops && ops->host_stream_close) - ops->host_stream_close(sdev, substream); + snd_sof_pcm_platform_close(sdev, substream); mutex_lock(&spcm->mutex); pm_runtime_mark_last_busy(sdev->dev); @@ -382,8 +375,8 @@ static int sof_pcm_new(struct snd_soc_pcm_runtime *rtd) struct snd_soc_tplg_stream_caps *caps; int ret = 0, stream = SNDRV_PCM_STREAM_PLAYBACK; + /* find SOF PCM for this RTD */ spcm = snd_sof_find_spcm_dai(sdev, rtd); - if (!spcm) { dev_warn(sdev->dev, "warn: can't find PCM with DAI ID %d\n", rtd->dai_link->id); @@ -486,6 +479,7 @@ static void sof_pcm_free(struct snd_pcm *pcm) snd_sof_free_topology(sdev); } +/* fixup the BE DAI link to match any values from topology */ static int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params) { @@ -499,8 +493,10 @@ static int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_sof_dai *dai = snd_sof_find_dai(sdev, (char *)rtd->dai_link->name); + /* no topology exists for this BE, try a common configuration */ if (!dai) { - dev_err(sdev->dev, "No DAI is found!\n"); + dev_err(sdev->dev, "error: no topology found for BE DAI %s config\n", + rtd->dai_link->name); /* set 48k, stereo, 16bits by default */ rate->min = 48000; @@ -512,7 +508,7 @@ static int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, snd_mask_none(fmt); snd_mask_set(fmt, SNDRV_PCM_FORMAT_S16_LE); - return -EINVAL; + return 0; } /* read format from topology */ From 81063c85e9ed7f63175547607572dfc6094e5eaa Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Mon, 2 Jul 2018 15:30:49 +0100 Subject: [PATCH 3/7] [SQUASHME] ASoC: sof: loader: cleanup - add comments and reorder funcs Add comments describing funcs/code blocks and reorder funcs so features are grouped. Signed-off-by: Liam Girdwood --- sound/soc/sof/loader.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sound/soc/sof/loader.c b/sound/soc/sof/loader.c index 82d6c6ccc65fb2..4bc7d7ac8ff59c 100644 --- a/sound/soc/sof/loader.c +++ b/sound/soc/sof/loader.c @@ -6,6 +6,8 @@ * Copyright(c) 2017 Intel Corporation. All rights reserved. * * Author: Liam Girdwood + * + * Generic firmware loader. */ #include @@ -42,6 +44,7 @@ static int get_ext_windows(struct snd_sof_dev *sdev, return ret; } +/* parse the extended FW boot data structures from FW boot message */ int snd_sof_fw_parse_ext_data(struct snd_sof_dev *sdev, u32 offset) { struct sof_ipc_ext_data_hdr *ext_hdr; @@ -279,5 +282,6 @@ EXPORT_SYMBOL(snd_sof_run_firmware); void snd_sof_fw_unload(struct snd_sof_dev *sdev) { + /* TODO: support module unloading at runtime */ } EXPORT_SYMBOL(snd_sof_fw_unload); From dc9bfad004772168c81a8cdb1b178c813d6a8119 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Mon, 2 Jul 2018 15:30:59 +0100 Subject: [PATCH 4/7] [SQUASHME] ASoC: sof: ipc: cleanup - add comments and reorder funcs Add comments describing funcs/code blocks and reorder funcs so features are grouped. Signed-off-by: Liam Girdwood --- sound/soc/sof/ipc.c | 364 +++++++++++++++++++++++++------------------- 1 file changed, 206 insertions(+), 158 deletions(-) diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index bd646c23cf9fd2..f0c90a7f820b2b 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -6,6 +6,9 @@ * Copyright(c) 2017 Intel Corporation. All rights reserved. * * Author: Liam Girdwood + * + * Generic IPC layer that can work over MMIO and SPI/I2C. PHY layer provided + * by platform driver code. */ #include @@ -31,11 +34,20 @@ #include "sof-priv.h" #include "ops.h" -/* IPC message timeout (msecs) */ +/* + * IPC message default size and timeout (msecs). + * TODO: allow platforms to set size and timeout. + */ #define IPC_TIMEOUT_MSECS 300 - #define IPC_EMPTY_LIST_SIZE 8 +static void ipc_trace_message(struct snd_sof_dev *sdev, u32 msg_id); +static void ipc_stream_message(struct snd_sof_dev *sdev, u32 msg_cmd); + +/* + * IPC message Tx/Rx message handling. + */ + /* SOF generic IPC data */ struct snd_sof_ipc { struct snd_sof_dev *sdev; @@ -59,6 +71,7 @@ static struct snd_sof_ipc_msg *msg_get_empty(struct snd_sof_ipc *ipc) { struct snd_sof_ipc_msg *msg = NULL; + /* get first empty message in the list */ if (!list_empty(&ipc->empty_list)) { msg = list_first_entry(&ipc->empty_list, struct snd_sof_ipc_msg, list); @@ -68,6 +81,7 @@ static struct snd_sof_ipc_msg *msg_get_empty(struct snd_sof_ipc *ipc) return msg; } +/* wait for IPC message reply */ static int tx_wait_done(struct snd_sof_ipc *ipc, struct snd_sof_ipc_msg *msg, void *reply_data) { @@ -111,6 +125,7 @@ static int tx_wait_done(struct snd_sof_ipc *ipc, struct snd_sof_ipc_msg *msg, return ret; } +/* send IPC message from host to DSP */ int sof_ipc_tx_message(struct snd_sof_ipc *ipc, u32 header, void *msg_data, size_t msg_bytes, void *reply_data, size_t reply_bytes) @@ -121,6 +136,7 @@ int sof_ipc_tx_message(struct snd_sof_ipc *ipc, u32 header, spin_lock_irqsave(&sdev->ipc_lock, flags); + /* get an empty message */ msg = msg_get_empty(ipc); if (!msg) { spin_unlock_irqrestore(&sdev->ipc_lock, flags); @@ -132,9 +148,11 @@ int sof_ipc_tx_message(struct snd_sof_ipc *ipc, u32 header, msg->reply_size = reply_bytes; msg->complete = false; + /* attach any data */ if (msg_bytes) memcpy(msg->msg_data, msg_data, msg_bytes); + /* add message to transmit list */ list_add_tail(&msg->list, &ipc->tx_list); /* schedule the messgae if not busy */ @@ -143,10 +161,12 @@ int sof_ipc_tx_message(struct snd_sof_ipc *ipc, u32 header, spin_unlock_irqrestore(&sdev->ipc_lock, flags); + /* now wait for completion */ return tx_wait_done(ipc, msg, reply_data); } EXPORT_SYMBOL(sof_ipc_tx_message); +/* send next IPC message in list */ static void ipc_tx_next_msg(struct work_struct *work) { struct snd_sof_ipc *ipc = @@ -156,19 +176,22 @@ static void ipc_tx_next_msg(struct work_struct *work) spin_lock_irq(&sdev->ipc_lock); + /* send message if HW read and message in TX list */ if (list_empty(&ipc->tx_list)) goto out; + /* sned first message in TX list */ msg = list_first_entry(&ipc->tx_list, struct snd_sof_ipc_msg, list); list_move(&msg->list, &ipc->reply_list); - snd_sof_dsp_send_msg(sdev, msg); + dev_dbg(sdev->dev, "ipc: send 0x%x\n", msg->header); out: spin_unlock_irq(&sdev->ipc_lock); } +/* find original TX message from DSP reply */ struct snd_sof_ipc_msg *sof_ipc_reply_find_msg(struct snd_sof_ipc *ipc, u32 header) { @@ -192,7 +215,7 @@ struct snd_sof_ipc_msg *sof_ipc_reply_find_msg(struct snd_sof_ipc *ipc, } EXPORT_SYMBOL(sof_ipc_reply_find_msg); -/* locks held by caller */ +/* mark IPC message as complete - locks held by caller */ void sof_ipc_tx_msg_reply_complete(struct snd_sof_ipc *ipc, struct snd_sof_ipc_msg *msg) { @@ -200,6 +223,7 @@ void sof_ipc_tx_msg_reply_complete(struct snd_sof_ipc *ipc, wake_up(&msg->waitq); } +/* drop all IPC messages in preparation for DSP stall/reset */ void sof_ipc_drop_all(struct snd_sof_ipc *ipc) { struct snd_sof_dev *sdev = ipc->sdev; @@ -223,6 +247,7 @@ void sof_ipc_drop_all(struct snd_sof_ipc *ipc) } EXPORT_SYMBOL(sof_ipc_drop_all); +/* handle reply message from DSP */ void snd_sof_ipc_reply(struct snd_sof_dev *sdev, u32 msg_id) { struct snd_sof_ipc_msg *msg; @@ -239,17 +264,105 @@ void snd_sof_ipc_reply(struct snd_sof_dev *sdev, u32 msg_id) } EXPORT_SYMBOL(snd_sof_ipc_reply); -int snd_sof_dsp_mailbox_init(struct snd_sof_dev *sdev, u32 dspbox, - size_t dspbox_size, u32 hostbox, - size_t hostbox_size) +/* DSP firmware has sent host a message */ +static void ipc_msgs_rx(struct work_struct *work) { - sdev->dsp_box.offset = dspbox; - sdev->dsp_box.size = dspbox_size; - sdev->host_box.offset = hostbox; - sdev->host_box.size = hostbox_size; - return 0; + struct snd_sof_ipc *ipc = + container_of(work, struct snd_sof_ipc, rx_kwork); + struct snd_sof_dev *sdev = ipc->sdev; + struct sof_ipc_hdr hdr; + u32 cmd, type; + int err = -EINVAL; + + /* read back header */ + snd_sof_dsp_mailbox_read(sdev, sdev->dsp_box.offset, &hdr, sizeof(hdr)); + + cmd = hdr.cmd & SOF_GLB_TYPE_MASK; + type = hdr.cmd & SOF_CMD_TYPE_MASK; + + /* check message type */ + switch (cmd) { + case SOF_IPC_GLB_REPLY: + dev_err(sdev->dev, "error: ipc reply unknown\n"); + break; + case SOF_IPC_FW_READY: + /* check for FW boot completion */ + if (!sdev->boot_complete) { + if (sdev->ops->fw_ready) + err = sdev->ops->fw_ready(sdev, cmd); + if (err < 0) { + dev_err(sdev->dev, "DSP firmware boot timeout %d\n", + err); + } else { + /* firmware boot completed OK */ + sdev->boot_complete = true; + dev_dbg(sdev->dev, "booting DSP firmware completed\n"); + wake_up(&sdev->boot_wait); + } + } + break; + case SOF_IPC_GLB_COMPOUND: + case SOF_IPC_GLB_TPLG_MSG: + case SOF_IPC_GLB_PM_MSG: + case SOF_IPC_GLB_COMP_MSG: + break; + case SOF_IPC_GLB_STREAM_MSG: + /* need to pass msg id into the function */ + ipc_stream_message(sdev, hdr.cmd); + break; + case SOF_IPC_GLB_TRACE_MSG: + ipc_trace_message(sdev, type); + break; + default: + dev_err(sdev->dev, "unknown DSP message 0x%x\n", cmd); + break; + } + + dev_dbg(sdev->dev, "ipc rx: 0x%x done\n", hdr.cmd); + + /* tell DSP we are done */ + snd_sof_dsp_cmd_done(sdev); } -EXPORT_SYMBOL(snd_sof_dsp_mailbox_init); + +/* schedule work to transmit any IPC in queue */ +void snd_sof_ipc_msgs_tx(struct snd_sof_dev *sdev) +{ + schedule_work(&sdev->ipc->tx_kwork); +} +EXPORT_SYMBOL(snd_sof_ipc_msgs_tx); + +/* schedule work to handle IPC from DSP */ +void snd_sof_ipc_msgs_rx(struct snd_sof_dev *sdev) +{ + schedule_work(&sdev->ipc->rx_kwork); +} +EXPORT_SYMBOL(snd_sof_ipc_msgs_rx); + +/* + * IPC trace mechanism. + */ + +static void ipc_trace_message(struct snd_sof_dev *sdev, u32 msg_id) +{ + struct sof_ipc_dma_trace_posn posn; + + switch (msg_id) { + case SOF_IPC_TRACE_DMA_POSITION: + /* read back full message */ + snd_sof_dsp_mailbox_read(sdev, sdev->dsp_box.offset, &posn, + sizeof(posn)); + snd_sof_trace_update_pos(sdev, &posn); + break; + default: + dev_err(sdev->dev, "error: unhandled trace message %x\n", + msg_id); + break; + } +} + +/* + * IPC stream position. + */ static void ipc_period_elapsed(struct snd_sof_dev *sdev, u32 msg_id) { @@ -293,6 +406,7 @@ static void ipc_period_elapsed(struct snd_sof_dev *sdev, u32 msg_id) snd_pcm_period_elapsed(spcm->stream[direction].substream); } +/* DSP notifies host of an XRUN within FW */ static void ipc_xrun(struct snd_sof_dev *sdev, u32 msg_id) { struct sof_ipc_stream_posn posn; @@ -300,7 +414,7 @@ static void ipc_xrun(struct snd_sof_dev *sdev, u32 msg_id) u32 posn_offset; int direction; - /* check if we have stream box */ + /* check if we have stream MMIO on this platform */ if (sdev->stream_box.size == 0) { /* read back full message */ snd_sof_dsp_mailbox_read(sdev, sdev->dsp_box.offset, &posn, @@ -330,12 +444,14 @@ static void ipc_xrun(struct snd_sof_dev *sdev, u32 msg_id) dev_dbg(sdev->dev, "posn XRUN: host %llx comp %d size %d\n", posn.host_posn, posn.xrun_comp_id, posn.xrun_size); - return; /* TODO: don't do anything yet until preload is working */ - +#if defined(CONFIG_SOC_SOF_DEBUG_XRUN_STOP) + /* stop PCM on XRUN - used for pipeline debug */ memcpy(&spcm->stream[direction].posn, &posn, sizeof(posn)); snd_pcm_stop_xrun(spcm->stream[direction].substream); +#endif } +/* stream notifications from DSP FW */ static void ipc_stream_message(struct snd_sof_dev *sdev, u32 msg_cmd) { /* get msg cmd type and msd id */ @@ -356,148 +472,7 @@ static void ipc_stream_message(struct snd_sof_dev *sdev, u32 msg_cmd) } } -static void ipc_trace_message(struct snd_sof_dev *sdev, u32 msg_id) -{ - struct sof_ipc_dma_trace_posn posn; - - switch (msg_id) { - case SOF_IPC_TRACE_DMA_POSITION: - /* read back full message */ - snd_sof_dsp_mailbox_read(sdev, sdev->dsp_box.offset, &posn, - sizeof(posn)); - snd_sof_trace_update_pos(sdev, &posn); - break; - default: - dev_err(sdev->dev, "error: unhandled trace message %x\n", - msg_id); - break; - } -} - -/* DSP firmware has sent host a message */ -static void ipc_msgs_rx(struct work_struct *work) -{ - struct snd_sof_ipc *ipc = - container_of(work, struct snd_sof_ipc, rx_kwork); - struct snd_sof_dev *sdev = ipc->sdev; - struct sof_ipc_hdr hdr; - u32 cmd, type; - int err = -EINVAL; - - /* read back header */ - snd_sof_dsp_mailbox_read(sdev, sdev->dsp_box.offset, &hdr, sizeof(hdr)); - - cmd = hdr.cmd & SOF_GLB_TYPE_MASK; - type = hdr.cmd & SOF_CMD_TYPE_MASK; - - switch (cmd) { - case SOF_IPC_GLB_REPLY: - dev_err(sdev->dev, "error: ipc reply unknown\n"); - break; - case SOF_IPC_FW_READY: - /* check for FW boot completion */ - if (!sdev->boot_complete) { - if (sdev->ops->fw_ready) - err = sdev->ops->fw_ready(sdev, cmd); - if (err < 0) { - dev_err(sdev->dev, "DSP firmware boot timeout %d\n", - err); - } else { - /* firmware boot completed OK */ - sdev->boot_complete = true; - dev_dbg(sdev->dev, "booting DSP firmware completed\n"); - wake_up(&sdev->boot_wait); - } - } - break; - case SOF_IPC_GLB_COMPOUND: - case SOF_IPC_GLB_TPLG_MSG: - case SOF_IPC_GLB_PM_MSG: - case SOF_IPC_GLB_COMP_MSG: - break; - case SOF_IPC_GLB_STREAM_MSG: - /* need to pass msg id into the function */ - ipc_stream_message(sdev, hdr.cmd); - break; - case SOF_IPC_GLB_TRACE_MSG: - ipc_trace_message(sdev, type); - break; - default: - dev_err(sdev->dev, "unknown DSP message 0x%x\n", cmd); - break; - } - - dev_dbg(sdev->dev, "ipc rx: 0x%x done\n", hdr.cmd); - - snd_sof_dsp_cmd_done(sdev); -} - -void snd_sof_ipc_msgs_tx(struct snd_sof_dev *sdev) -{ - schedule_work(&sdev->ipc->tx_kwork); -} -EXPORT_SYMBOL(snd_sof_ipc_msgs_tx); - -void snd_sof_ipc_msgs_rx(struct snd_sof_dev *sdev) -{ - schedule_work(&sdev->ipc->rx_kwork); -} -EXPORT_SYMBOL(snd_sof_ipc_msgs_rx); - -struct snd_sof_ipc *snd_sof_ipc_init(struct snd_sof_dev *sdev) -{ - struct snd_sof_ipc *ipc; - struct snd_sof_ipc_msg *msg; - int i; - - ipc = devm_kzalloc(sdev->dev, sizeof(*ipc), GFP_KERNEL); - if (!ipc) - return NULL; - - INIT_LIST_HEAD(&ipc->tx_list); - INIT_LIST_HEAD(&ipc->reply_list); - INIT_LIST_HEAD(&ipc->empty_list); - init_waitqueue_head(&ipc->wait_txq); - INIT_WORK(&ipc->tx_kwork, ipc_tx_next_msg); - INIT_WORK(&ipc->rx_kwork, ipc_msgs_rx); - ipc->sdev = sdev; - - /* pre-allocate messages */ - dev_dbg(sdev->dev, "pre-allocate %d IPC messages\n", - IPC_EMPTY_LIST_SIZE); - msg = devm_kzalloc(sdev->dev, sizeof(struct snd_sof_ipc_msg) * - IPC_EMPTY_LIST_SIZE, GFP_KERNEL); - if (!msg) - return NULL; - - /* pre-allocate message data */ - for (i = 0; i < IPC_EMPTY_LIST_SIZE; i++) { - msg->msg_data = devm_kzalloc(sdev->dev, PAGE_SIZE, GFP_KERNEL); - if (!msg->msg_data) - return NULL; - - msg->reply_data = devm_kzalloc(sdev->dev, PAGE_SIZE, - GFP_KERNEL); - if (!msg->reply_data) - return NULL; - - init_waitqueue_head(&msg->waitq); - list_add(&msg->list, &ipc->empty_list); - msg++; - } - - return ipc; -} -EXPORT_SYMBOL(snd_sof_ipc_init); - -void snd_sof_ipc_free(struct snd_sof_dev *sdev) -{ - /* TODO: send IPC to prepare DSP for shutdown */ - cancel_work_sync(&sdev->ipc->tx_kwork); - cancel_work_sync(&sdev->ipc->rx_kwork); -} -EXPORT_SYMBOL(snd_sof_ipc_free); - +/* get stream position IPC - use faster MMIO method if available on platform */ int snd_sof_ipc_stream_posn(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm, int direction, struct sof_ipc_stream_posn *posn) @@ -524,6 +499,10 @@ int snd_sof_ipc_stream_posn(struct snd_sof_dev *sdev, } EXPORT_SYMBOL(snd_sof_ipc_stream_posn); +/* + * IPC get()/set() for kcontrols. + */ + int snd_sof_ipc_set_comp_data(struct snd_sof_ipc *ipc, struct snd_sof_control *scontrol, u32 ipc_cmd, enum sof_ipc_ctrl_type ctrl_type, @@ -607,3 +586,72 @@ int snd_sof_ipc_get_comp_data(struct snd_sof_ipc *ipc, return 0; } EXPORT_SYMBOL(snd_sof_ipc_get_comp_data); + +/* + * IPC layer enumeration. + */ + +int snd_sof_dsp_mailbox_init(struct snd_sof_dev *sdev, u32 dspbox, + size_t dspbox_size, u32 hostbox, + size_t hostbox_size) +{ + sdev->dsp_box.offset = dspbox; + sdev->dsp_box.size = dspbox_size; + sdev->host_box.offset = hostbox; + sdev->host_box.size = hostbox_size; + return 0; +} +EXPORT_SYMBOL(snd_sof_dsp_mailbox_init); + +struct snd_sof_ipc *snd_sof_ipc_init(struct snd_sof_dev *sdev) +{ + struct snd_sof_ipc *ipc; + struct snd_sof_ipc_msg *msg; + int i; + + ipc = devm_kzalloc(sdev->dev, sizeof(*ipc), GFP_KERNEL); + if (!ipc) + return NULL; + + INIT_LIST_HEAD(&ipc->tx_list); + INIT_LIST_HEAD(&ipc->reply_list); + INIT_LIST_HEAD(&ipc->empty_list); + init_waitqueue_head(&ipc->wait_txq); + INIT_WORK(&ipc->tx_kwork, ipc_tx_next_msg); + INIT_WORK(&ipc->rx_kwork, ipc_msgs_rx); + ipc->sdev = sdev; + + /* pre-allocate messages */ + dev_dbg(sdev->dev, "pre-allocate %d IPC messages\n", + IPC_EMPTY_LIST_SIZE); + msg = devm_kzalloc(sdev->dev, sizeof(struct snd_sof_ipc_msg) * + IPC_EMPTY_LIST_SIZE, GFP_KERNEL); + if (!msg) + return NULL; + + /* pre-allocate message data */ + for (i = 0; i < IPC_EMPTY_LIST_SIZE; i++) { + msg->msg_data = devm_kzalloc(sdev->dev, PAGE_SIZE, GFP_KERNEL); + if (!msg->msg_data) + return NULL; + + msg->reply_data = devm_kzalloc(sdev->dev, PAGE_SIZE, + GFP_KERNEL); + if (!msg->reply_data) + return NULL; + + init_waitqueue_head(&msg->waitq); + list_add(&msg->list, &ipc->empty_list); + msg++; + } + + return ipc; +} +EXPORT_SYMBOL(snd_sof_ipc_init); + +void snd_sof_ipc_free(struct snd_sof_dev *sdev) +{ + cancel_work_sync(&sdev->ipc->tx_kwork); + cancel_work_sync(&sdev->ipc->rx_kwork); +} +EXPORT_SYMBOL(snd_sof_ipc_free); From 621a20389a496720ce1193eff6f00b172a5481e0 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Mon, 2 Jul 2018 15:31:15 +0100 Subject: [PATCH 5/7] [SQUASHME] ASoC: sof: ops: cleanup - add comments and reorder funcs Add comments describing funcs/code blocks and reorder funcs so features are grouped. Signed-off-by: Liam Girdwood --- sound/soc/sof/ops.h | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/sound/soc/sof/ops.h b/sound/soc/sof/ops.h index 1a00a4b7d8037f..340f1ccc40447f 100644 --- a/sound/soc/sof/ops.h +++ b/sound/soc/sof/ops.h @@ -219,6 +219,51 @@ static inline int snd_sof_dma_trace_trigger(struct snd_sof_dev *sdev, int cmd) return 0; } +/* host PCM ops */ +static inline int +snd_sof_pcm_platform_open(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream) +{ + if (sdev->ops && sdev->ops->pcm_open) + return sdev->ops->pcm_open(sdev, substream); + else + return 0; +} + +/* disconnect pcm substream to a host stream */ +static inline int +snd_sof_pcm_platform_close(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream) +{ + if (sdev->ops && sdev->ops->pcm_close) + return sdev->ops->pcm_close(sdev, substream); + else + return 0; +} + +/* host stream hw params */ +static inline int +snd_sof_pcm_platform_hw_params(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + if (sdev->ops && sdev->ops->pcm_hw_params) + return sdev->ops->pcm_hw_params(sdev, substream, params); + else + return 0; +} + +/* host stream trigger */ +static inline int +snd_sof_pcm_platform_trigger(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream, int cmd) +{ + if (sdev->ops && sdev->ops->pcm_trigger) + return sdev->ops->pcm_trigger(sdev, substream, cmd); + else + return 0; +} + int snd_sof_dsp_update_bits_unlocked(struct snd_sof_dev *sdev, u32 bar, u32 offset, u32 mask, u32 value); From cb84cdb5a892b05bc2db12fc57740a319a535115 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Mon, 2 Jul 2018 15:31:29 +0100 Subject: [PATCH 6/7] [SQUASHME] ASoC: sof: skl, cnl, apl: cleanup - add comments and reorder funcs Add comments describing funcs/code blocks and reorder funcs so features are grouped. Signed-off-by: Liam Girdwood --- sound/soc/sof/intel/apl.c | 8 ++++---- sound/soc/sof/intel/cnl.c | 8 ++++---- sound/soc/sof/intel/skl.c | 8 ++++---- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/sound/soc/sof/intel/apl.c b/sound/soc/sof/intel/apl.c index d36e30d2a8b388..358c6904f1115e 100644 --- a/sound/soc/sof/intel/apl.c +++ b/sound/soc/sof/intel/apl.c @@ -77,10 +77,10 @@ struct snd_sof_dsp_ops sof_apl_ops = { .dbg_dump = hda_dsp_dump, /* stream callbacks */ - .host_stream_open = hda_dsp_pcm_open, - .host_stream_close = hda_dsp_pcm_close, - .host_stream_hw_params = hda_dsp_pcm_hw_params, - .host_stream_trigger = hda_dsp_pcm_trigger, + .pcm_open = hda_dsp_pcm_open, + .pcm_close = hda_dsp_pcm_close, + .pcm_hw_params = hda_dsp_pcm_hw_params, + .pcm_trigger = hda_dsp_pcm_trigger, /* firmware loading */ .load_firmware = hda_dsp_cl_load_fw, diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index 80d6cc772fd74a..5fad5fcd02327c 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -205,10 +205,10 @@ struct snd_sof_dsp_ops sof_cnl_ops = { .dbg_dump = hda_dsp_dump, /* stream callbacks */ - .host_stream_open = hda_dsp_pcm_open, - .host_stream_close = hda_dsp_pcm_close, - .host_stream_hw_params = hda_dsp_pcm_hw_params, - .host_stream_trigger = hda_dsp_pcm_trigger, + .pcm_open = hda_dsp_pcm_open, + .pcm_close = hda_dsp_pcm_close, + .pcm_hw_params = hda_dsp_pcm_hw_params, + .pcm_trigger = hda_dsp_pcm_trigger, /* firmware loading */ .load_firmware = hda_dsp_cl_load_fw, diff --git a/sound/soc/sof/intel/skl.c b/sound/soc/sof/intel/skl.c index d4b6de626456b1..2e62a85bafc6cc 100644 --- a/sound/soc/sof/intel/skl.c +++ b/sound/soc/sof/intel/skl.c @@ -82,10 +82,10 @@ struct snd_sof_dsp_ops sof_skl_ops = { .dbg_dump = hda_dsp_dump, /* stream callbacks */ - .host_stream_open = hda_dsp_pcm_open, - .host_stream_close = hda_dsp_pcm_close, - .host_stream_hw_params = hda_dsp_pcm_hw_params, - .host_stream_trigger = hda_dsp_pcm_trigger, + .pcm_open = hda_dsp_pcm_open, + .pcm_close = hda_dsp_pcm_close, + .pcm_hw_params = hda_dsp_pcm_hw_params, + .pcm_trigger = hda_dsp_pcm_trigger, /* firmware loading */ .load_firmware = hda_dsp_cl_load_fw, From b66e8ef1122d04210a1829c9245b0e1d7b37b5bc Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Thu, 5 Jul 2018 16:39:48 +0100 Subject: [PATCH 7/7] [SQUASH] ASoC: SOF: Kconfig: cleanup Kconfig debug options Signed-off-by: Liam Girdwood --- sound/soc/sof/Kconfig | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/Kconfig b/sound/soc/sof/Kconfig index bdae3f5969915b..cec2ea91df14dc 100644 --- a/sound/soc/sof/Kconfig +++ b/sound/soc/sof/Kconfig @@ -7,7 +7,6 @@ config SND_SOC_SOF_ACPI config SND_SOC_SOF_PLATFORM tristate - config SND_SOC_SOF tristate "Sound Open Firmware Support" default m @@ -29,9 +28,19 @@ config SND_SOC_SOF_NOCODEC Say Y if you need this nocodec fallback option If unsure select "N". +config SND_SOC_SOF_DEBUG + bool "SOF debugging features" + depends on SND_SOC_SOF + help + This option can be used to enable or disable individual SOF firmware + and driver debugging options. + Say Y if you are debugging SOF FW or drivers. + If unsure select "N". + config SND_SOC_SOF_FORCE_NOCODEC_MODE - tristate "SOF force nocodec Mode" + bool "SOF force nocodec Mode" depends on SND_SOC_SOF_NOCODEC + depends on SND_SOC_SOF_DEBUG help This forces SOF to use dummy/nocodec as machine driver, even though there is a codec detected on the real platform. This is @@ -41,5 +50,14 @@ config SND_SOC_SOF_FORCE_NOCODEC_MODE Say Y if you need this force nocodec mode option If unsure select "N". +config SND_SOC_SOF_DEBUG_XRUN_STOP + bool "SOF stop on XRUN" + depends on SND_SOC_SOF_DEBUG + help + This option forces PCMs to stop on any XRUN event. This is useful to + preserve any trace data ond pipeline status prior to the XRUN. + Say Y if you are debugging SOF FW pipeline XRUNs. + If unsure select "N". + source "sound/soc/sof/intel/Kconfig" source "sound/soc/sof/xtensa/Kconfig"