Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ASoC: SOF: Intel: hda: improve code loader and prepare for SoundWire BPT reuse #4697

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 56 additions & 24 deletions sound/soc/sof/intel/hda-loader.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,13 @@ static void hda_ssp_set_cbp_cfp(struct snd_sof_dev *sdev)
}
}

struct hdac_ext_stream *hda_cl_stream_prepare(struct snd_sof_dev *sdev, unsigned int format,
unsigned int size, struct snd_dma_buffer *dmab,
int direction)
struct hdac_ext_stream *hda_cl_prepare(struct device *dev, unsigned int format,
unsigned int size, struct snd_dma_buffer *dmab,
int direction, bool is_iccmax)
{
struct snd_sof_dev *sdev = dev_get_drvdata(dev);
struct hdac_ext_stream *hext_stream;
struct hdac_stream *hstream;
struct pci_dev *pci = to_pci_dev(sdev->dev);
int ret;

hext_stream = hda_dsp_stream_get(sdev, direction, 0);
Expand All @@ -62,7 +62,7 @@ struct hdac_ext_stream *hda_cl_stream_prepare(struct snd_sof_dev *sdev, unsigned
hstream->substream = NULL;

/* allocate DMA buffer */
ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV_SG, &pci->dev, size, dmab);
ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV_SG, dev, size, dmab);
if (ret < 0) {
dev_err(sdev->dev, "error: memory alloc failed: %d\n", ret);
goto out_put;
Expand All @@ -72,7 +72,7 @@ struct hdac_ext_stream *hda_cl_stream_prepare(struct snd_sof_dev *sdev, unsigned
hstream->format_val = format;
hstream->bufsize = size;

if (direction == SNDRV_PCM_STREAM_CAPTURE) {
if (is_iccmax) {
ret = hda_dsp_iccmax_stream_hw_params(sdev, hext_stream, dmab, NULL);
if (ret < 0) {
dev_err(sdev->dev, "error: iccmax stream prepare failed: %d\n", ret);
Expand All @@ -95,6 +95,7 @@ struct hdac_ext_stream *hda_cl_stream_prepare(struct snd_sof_dev *sdev, unsigned
hda_dsp_stream_put(sdev, direction, hstream->stream_tag);
return ERR_PTR(ret);
}
EXPORT_SYMBOL_NS(hda_cl_prepare, SND_SOC_SOF_INTEL_HDA_COMMON);

/*
* first boot sequence has some extra steps.
Expand Down Expand Up @@ -219,15 +220,20 @@ int cl_dsp_init(struct snd_sof_dev *sdev, int stream_tag, bool imr_boot)
return ret;
}

static int cl_trigger(struct snd_sof_dev *sdev,
struct hdac_ext_stream *hext_stream, int cmd)
int hda_cl_trigger(struct device *dev, struct hdac_ext_stream *hext_stream, int cmd)
{
struct snd_sof_dev *sdev = dev_get_drvdata(dev);
struct hdac_stream *hstream = &hext_stream->hstream;
int sd_offset = SOF_STREAM_SD_OFFSET(hstream);
struct sof_intel_hda_stream *hda_stream;

/* code loader is special case that reuses stream ops */
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
hda_stream = container_of(hext_stream, struct sof_intel_hda_stream,
hext_stream);
reinit_completion(&hda_stream->ioc);

snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTCTL,
1 << hstream->index,
1 << hstream->index);
Expand All @@ -245,10 +251,12 @@ static int cl_trigger(struct snd_sof_dev *sdev,
return hda_dsp_stream_trigger(sdev, hext_stream, cmd);
}
}
EXPORT_SYMBOL_NS(hda_cl_trigger, SND_SOC_SOF_INTEL_HDA_COMMON);

int hda_cl_cleanup(struct snd_sof_dev *sdev, struct snd_dma_buffer *dmab,
int hda_cl_cleanup(struct device *dev, struct snd_dma_buffer *dmab,
struct hdac_ext_stream *hext_stream)
{
struct snd_sof_dev *sdev = dev_get_drvdata(dev);
struct hdac_stream *hstream = &hext_stream->hstream;
int sd_offset = SOF_STREAM_SD_OFFSET(hstream);
int ret = 0;
Expand Down Expand Up @@ -277,20 +285,40 @@ int hda_cl_cleanup(struct snd_sof_dev *sdev, struct snd_dma_buffer *dmab,

return ret;
}
EXPORT_SYMBOL_NS(hda_cl_cleanup, SND_SOC_SOF_INTEL_HDA_COMMON);

#define HDA_CL_DMA_IOC_TIMEOUT_MS 500

int hda_cl_copy_fw(struct snd_sof_dev *sdev, struct hdac_ext_stream *hext_stream)
{
struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
const struct sof_intel_dsp_desc *chip = hda->desc;
struct sof_intel_hda_stream *hda_stream;
unsigned long time_left;
unsigned int reg;
int ret, status;

ret = cl_trigger(sdev, hext_stream, SNDRV_PCM_TRIGGER_START);
hda_stream = container_of(hext_stream, struct sof_intel_hda_stream,
hext_stream);

dev_dbg(sdev->dev, "Code loader DMA starting\n");

ret = hda_cl_trigger(sdev->dev, hext_stream, SNDRV_PCM_TRIGGER_START);
if (ret < 0) {
dev_err(sdev->dev, "error: DMA trigger start failed\n");
return ret;
}

/* Wait for completion of transfer */
time_left = wait_for_completion_timeout(&hda_stream->ioc,
msecs_to_jiffies(HDA_CL_DMA_IOC_TIMEOUT_MS));

if (!time_left) {
dev_err(sdev->dev, "Code loader DMA did not complete\n");
return -ETIMEDOUT;
}
dev_dbg(sdev->dev, "Code loader DMA done, waiting for FW_ENTERED status\n");

status = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR,
chip->rom_status_reg, reg,
(FSR_TO_STATE_CODE(reg) == FSR_STATE_FW_ENTERED),
Expand All @@ -306,13 +334,17 @@ int hda_cl_copy_fw(struct snd_sof_dev *sdev, struct hdac_ext_stream *hext_stream
dev_err(sdev->dev,
"%s: timeout with rom_status_reg (%#x) read\n",
__func__, chip->rom_status_reg);
} else {
dev_dbg(sdev->dev, "Code loader FW_ENTERED status\n");
plbossart marked this conversation as resolved.
Show resolved Hide resolved
}

ret = cl_trigger(sdev, hext_stream, SNDRV_PCM_TRIGGER_STOP);
ret = hda_cl_trigger(sdev->dev, hext_stream, SNDRV_PCM_TRIGGER_STOP);
if (ret < 0) {
dev_err(sdev->dev, "error: DMA trigger stop failed\n");
if (!status)
status = ret;
} else {
dev_dbg(sdev->dev, "Code loader DMA stopped\n");
}

return status;
Expand All @@ -333,8 +365,8 @@ int hda_dsp_cl_boot_firmware_iccmax(struct snd_sof_dev *sdev)
* Prepare capture stream for ICCMAX. We do not need to store
* the data, so use a buffer of PAGE_SIZE for receiving.
*/
iccmax_stream = hda_cl_stream_prepare(sdev, HDA_CL_STREAM_FORMAT, PAGE_SIZE,
&dmab_bdl, SNDRV_PCM_STREAM_CAPTURE);
iccmax_stream = hda_cl_prepare(sdev->dev, HDA_CL_STREAM_FORMAT, PAGE_SIZE,
&dmab_bdl, SNDRV_PCM_STREAM_CAPTURE, true);
if (IS_ERR(iccmax_stream)) {
dev_err(sdev->dev, "error: dma prepare for ICCMAX stream failed\n");
return PTR_ERR(iccmax_stream);
Expand All @@ -346,7 +378,7 @@ int hda_dsp_cl_boot_firmware_iccmax(struct snd_sof_dev *sdev)
* Perform iccmax stream cleanup. This should be done even if firmware loading fails.
* If the cleanup also fails, we return the initial error
*/
ret1 = hda_cl_cleanup(sdev, &dmab_bdl, iccmax_stream);
ret1 = hda_cl_cleanup(sdev->dev, &dmab_bdl, iccmax_stream);
if (ret1 < 0) {
dev_err(sdev->dev, "error: ICCMAX stream cleanup failed\n");

Expand Down Expand Up @@ -418,9 +450,9 @@ int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev)
init_waitqueue_head(&sdev->boot_wait);

/* prepare DMA for code loader stream */
hext_stream = hda_cl_stream_prepare(sdev, HDA_CL_STREAM_FORMAT,
stripped_firmware.size,
&dmab, SNDRV_PCM_STREAM_PLAYBACK);
hext_stream = hda_cl_prepare(sdev->dev, HDA_CL_STREAM_FORMAT,
stripped_firmware.size,
&dmab, SNDRV_PCM_STREAM_PLAYBACK, false);
if (IS_ERR(hext_stream)) {
dev_err(sdev->dev, "error: dma prepare for fw loading failed\n");
return PTR_ERR(hext_stream);
Expand Down Expand Up @@ -493,7 +525,7 @@ int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev)
* This should be done even if firmware loading fails.
* If the cleanup also fails, we return the initial error
*/
ret1 = hda_cl_cleanup(sdev, &dmab, hext_stream);
ret1 = hda_cl_cleanup(sdev->dev, &dmab, hext_stream);
if (ret1 < 0) {
dev_err(sdev->dev, "error: Code loader DSP cleanup failed\n");

Expand Down Expand Up @@ -534,9 +566,9 @@ int hda_dsp_ipc4_load_library(struct snd_sof_dev *sdev,
stripped_firmware.size = fw_lib->sof_fw.fw->size - fw_lib->sof_fw.payload_offset;

/* prepare DMA for code loader stream */
hext_stream = hda_cl_stream_prepare(sdev, HDA_CL_STREAM_FORMAT,
stripped_firmware.size,
&dmab, SNDRV_PCM_STREAM_PLAYBACK);
hext_stream = hda_cl_prepare(sdev->dev, HDA_CL_STREAM_FORMAT,
stripped_firmware.size,
&dmab, SNDRV_PCM_STREAM_PLAYBACK, false);
if (IS_ERR(hext_stream)) {
dev_err(sdev->dev, "%s: DMA prepare failed\n", __func__);
return PTR_ERR(hext_stream);
Expand Down Expand Up @@ -579,7 +611,7 @@ int hda_dsp_ipc4_load_library(struct snd_sof_dev *sdev,
goto cleanup;
}

ret = cl_trigger(sdev, hext_stream, SNDRV_PCM_TRIGGER_START);
ret = hda_cl_trigger(sdev->dev, hext_stream, SNDRV_PCM_TRIGGER_START);
if (ret < 0) {
dev_err(sdev->dev, "%s: DMA trigger start failed\n", __func__);
goto cleanup;
Expand All @@ -596,7 +628,7 @@ int hda_dsp_ipc4_load_library(struct snd_sof_dev *sdev,
ret = sof_ipc_tx_message_no_reply(sdev->ipc, &msg, 0);

/* Stop the DMA channel */
ret1 = cl_trigger(sdev, hext_stream, SNDRV_PCM_TRIGGER_STOP);
ret1 = hda_cl_trigger(sdev->dev, hext_stream, SNDRV_PCM_TRIGGER_STOP);
if (ret1 < 0) {
dev_err(sdev->dev, "%s: DMA trigger stop failed\n", __func__);
if (!ret)
Expand All @@ -605,7 +637,7 @@ int hda_dsp_ipc4_load_library(struct snd_sof_dev *sdev,

cleanup:
/* clean up even in case of error and return the first error */
ret1 = hda_cl_cleanup(sdev, &dmab, hext_stream);
ret1 = hda_cl_cleanup(sdev->dev, &dmab, hext_stream);
if (ret1 < 0) {
dev_err(sdev->dev, "%s: Code loader DSP cleanup failed\n", __func__);

Expand Down
24 changes: 20 additions & 4 deletions sound/soc/sof/intel/hda-stream.c
Original file line number Diff line number Diff line change
Expand Up @@ -764,12 +764,27 @@ static bool hda_dsp_stream_check(struct hdac_bus *bus, u32 status)
writeb(sd_status, s->sd_addr + SOF_HDA_ADSP_REG_SD_STS);

active = true;
if ((!s->substream && !s->cstream) ||
!s->running ||
(sd_status & SOF_HDA_CL_DMA_SD_INT_COMPLETE) == 0)
if (!s->running)
continue;
if ((sd_status & SOF_HDA_CL_DMA_SD_INT_COMPLETE) == 0)
continue;
if (!s->substream && !s->cstream) {
/*
* when no substream is found, the DMA may used for code loading
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo "may be used..."

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i'll add a fixup

* or data transfers which can rely on wait_for_completion()
*/
struct sof_intel_hda_stream *hda_stream;
struct hdac_ext_stream *hext_stream;

hext_stream = stream_to_hdac_ext_stream(s);
hda_stream = container_of(hext_stream, struct sof_intel_hda_stream,
hext_stream);

complete(&hda_stream->ioc);
continue;
}

/* Inform ALSA only in case not do that with IPC */
/* Inform ALSA only if the IPC position is not used */
if (s->substream && sof_hda->no_ipc_position) {
snd_sof_pcm_period_elapsed(s->substream);
} else if (s->cstream) {
Expand Down Expand Up @@ -879,6 +894,7 @@ int hda_dsp_stream_init(struct snd_sof_dev *sdev)
return -ENOMEM;

hda_stream->sdev = sdev;
init_completion(&hda_stream->ioc);

hext_stream = &hda_stream->hext_stream;

Expand Down
13 changes: 9 additions & 4 deletions sound/soc/sof/intel/hda.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#ifndef __SOF_INTEL_HDA_H
#define __SOF_INTEL_HDA_H

#include <linux/completion.h>
#include <linux/soundwire/sdw.h>
#include <linux/soundwire/sdw_intel.h>
#include <sound/compress_driver.h>
Expand Down Expand Up @@ -559,6 +560,7 @@ struct sof_intel_hda_stream {
struct sof_intel_stream sof_intel_stream;
int host_reserved; /* reserve host DMA channel */
u32 flags;
struct completion ioc;
plbossart marked this conversation as resolved.
Show resolved Hide resolved
};

#define hstream_to_sof_hda_stream(hstream) \
Expand Down Expand Up @@ -695,10 +697,13 @@ int hda_dsp_ipc_cmd_done(struct snd_sof_dev *sdev, int dir);
int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev);
int hda_dsp_cl_boot_firmware_iccmax(struct snd_sof_dev *sdev);
int hda_cl_copy_fw(struct snd_sof_dev *sdev, struct hdac_ext_stream *hext_stream);
struct hdac_ext_stream *hda_cl_stream_prepare(struct snd_sof_dev *sdev, unsigned int format,
unsigned int size, struct snd_dma_buffer *dmab,
int direction);
int hda_cl_cleanup(struct snd_sof_dev *sdev, struct snd_dma_buffer *dmab,

struct hdac_ext_stream *hda_cl_prepare(struct device *dev, unsigned int format,
unsigned int size, struct snd_dma_buffer *dmab,
int direction, bool is_iccmax);
int hda_cl_trigger(struct device *dev, struct hdac_ext_stream *hext_stream, int cmd);

int hda_cl_cleanup(struct device *dev, struct snd_dma_buffer *dmab,
struct hdac_ext_stream *hext_stream);
int cl_dsp_init(struct snd_sof_dev *sdev, int stream_tag, bool imr_boot);
#define HDA_CL_STREAM_FORMAT 0x40
Expand Down