[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#940726: marked as done (linux-source-5.2: Enable SOF audio driver and back-port fixes required to 5.2 kernel)



Your message dated Sun, 20 Oct 2019 22:05:41 +0000
with message-id <E1iMJKX-000Ibn-6b@fasolo.debian.org>
and subject line Bug#940726: fixed in linux 5.3.7-1
has caused the Debian Bug report #940726,
regarding linux-source-5.2: Enable SOF audio driver and back-port fixes required to 5.2 kernel
to be marked as done.

This means that you claim that the problem has been dealt with.
If this is not the case it is now your responsibility to reopen the
Bug report if necessary, and/or fix the problem forthwith.

(NB: If you are a system administrator and have no idea what this
message is talking about, this may indicate a serious mail system
misconfiguration somewhere. Please contact owner@bugs.debian.org
immediately.)


-- 
940726: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=940726
Debian Bug Tracking System
Contact owner@bugs.debian.org with problems
--- Begin Message ---
Package: linux-source-5.2
Version: 5.2.9-2~bpo10+1
Severity: important
Tags: patch

Dear Maintainer,

   * What led up to the situation?
The Lenovo X1 Carbon Gen 7 laptops use the Whiskeylake CPU and when testing
with Debian we found the audio was not working.
Whiskeylake requires the new SOF audio driver to be enabled - but some fixes
also need to be backported to prevent firmware load issues seen during suspend
and resume
Note we are using the buster-backports 5.2 kernel as SOF audio driver support
is not available in the earlier kernels.

   * What exactly did you do (or not do) that was effective (or
     ineffective)?
Enabled SOF audio driver kernel configs and rebuilt the kernel. Tested and
debugged the suspend/resume issue and identified the required commits from the
working 5.3 kernel.org kernel that are needed to fix the issue.

   * What was the outcome of this action?
Audio is working correctly. The driver appears stable

   * What outcome did you expect instead?
NA

Notes:
The patch I'm uploading is a combo of the following applied to 5.2:
https://github.com/thesofproject/linux/commit/c760776089f147c4d28875619f3a917c02d42307
https://github.com/thesofproject/linux/commit/bb1ea3b31c28a131a5f5a50dd325198645526b19
https://github.com/thesofproject/linux/commit/64632de9140e52b72781fefe542314db7cd29d8c
https://github.com/thesofproject/linux/commit/bf705eaa7ce07f9c132f8e367fc2fc46b7842528
https://github.com/thesofproject/linux/commit/38d0e9fc227c7876d09754863adc88aeca6dd205
https://github.com/thesofproject/linux/commit/f5dbba9fee801f4678a50d92c785f7f24d4ee2c6
https://github.com/thesofproject/linux/commit/7623ae793c28cc0928c5d1292542dbb92fc2e9e2

The kconfig snipped I'm also uploading is based on config settings from the SOF
team

This is my first bug raised against Debian - Lenovo are actively focussing on
getting Debian working on our systems so I'm hoping to get a lot more involved.
Please do let me know if I've made any mistakes or things I can improve on for
future bugs.

Thanks
Mrk Pearson



-- System Information:
Debian Release: 10.1
  APT prefers stable-updates
  APT policy: (500, 'stable-updates'), (500, 'stable')
Architecture: amd64 (x86_64)

Kernel: Linux 5.2.9 (SMP w/8 CPU cores)
Kernel taint flags: TAINT_UNSIGNED_MODULE
Locale: LANG=en_CA.UTF-8, LC_CTYPE=en_CA.UTF-8 (charmap=UTF-8), LANGUAGE=en_CA.UTF-8 (charmap=UTF-8)
Shell: /bin/sh linked to /usr/bin/dash
Init: systemd (via /run/systemd/system)
LSM: AppArmor: enabled

Versions of packages linux-source-5.2 depends on:
ii  binutils  2.31.1-16
ii  xz-utils  5.2.4-1

Versions of packages linux-source-5.2 recommends:
ii  bc                    1.07.1-2+b1
ii  bison                 2:3.3.2.dfsg-1
ii  flex                  2.6.4-6.2
ii  gcc                   4:8.3.0-1
ii  libc6-dev [libc-dev]  2.28-10
ii  linux-config-5.2      5.2.9-2~bpo10+1
ii  make                  4.2.1-1.2

Versions of packages linux-source-5.2 suggests:
ii  libncurses-dev [ncurses-dev]  6.1+20181013-2+deb10u1
pn  libqt4-dev                    <none>
pn  pkg-config                    <none>

-- no debconf information
diff -Naurp linux-source-5.2-orig/sound/soc/sof/control.c linux-source-5.2/sound/soc/sof/control.c
--- linux-source-5.2-orig/sound/soc/sof/control.c	2019-08-16 04:11:12.000000000 -0400
+++ linux-source-5.2/sound/soc/sof/control.c	2019-09-18 22:18:22.970932678 -0400
@@ -39,26 +39,8 @@ int snd_sof_volume_get(struct snd_kcontr
 	struct soc_mixer_control *sm =
 		(struct soc_mixer_control *)kcontrol->private_value;
 	struct snd_sof_control *scontrol = sm->dobj.private;
-	struct snd_sof_dev *sdev = scontrol->sdev;
 	struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
 	unsigned int i, channels = scontrol->num_channels;
-	int err, ret;
-
-	ret = pm_runtime_get_sync(sdev->dev);
-	if (ret < 0) {
-		dev_err_ratelimited(sdev->dev,
-				    "error: volume get failed to resume %d\n",
-				    ret);
-		pm_runtime_put_noidle(sdev->dev);
-		return ret;
-	}
-
-	/* get all the mixer data from DSP */
-	snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
-				      SOF_IPC_COMP_GET_VALUE,
-				      SOF_CTRL_TYPE_VALUE_CHAN_GET,
-				      SOF_CTRL_CMD_VOLUME,
-				      false);
 
 	/* read back each channel */
 	for (i = 0; i < channels; i++)
@@ -66,12 +48,6 @@ int snd_sof_volume_get(struct snd_kcontr
 			ipc_to_mixer(cdata->chanv[i].value,
 				     scontrol->volume_table, sm->max + 1);
 
-	pm_runtime_mark_last_busy(sdev->dev);
-	err = pm_runtime_put_autosuspend(sdev->dev);
-	if (err < 0)
-		dev_err_ratelimited(sdev->dev,
-				    "error: volume get failed to idle %d\n",
-				    err);
 	return 0;
 }
 
@@ -84,16 +60,6 @@ int snd_sof_volume_put(struct snd_kcontr
 	struct snd_sof_dev *sdev = scontrol->sdev;
 	struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
 	unsigned int i, channels = scontrol->num_channels;
-	int ret, err;
-
-	ret = pm_runtime_get_sync(sdev->dev);
-	if (ret < 0) {
-		dev_err_ratelimited(sdev->dev,
-				    "error: volume put failed to resume %d\n",
-				    ret);
-		pm_runtime_put_noidle(sdev->dev);
-		return ret;
-	}
 
 	/* update each channel */
 	for (i = 0; i < channels; i++) {
@@ -104,18 +70,13 @@ int snd_sof_volume_put(struct snd_kcontr
 	}
 
 	/* notify DSP of mixer updates */
-	snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
-				      SOF_IPC_COMP_SET_VALUE,
-				      SOF_CTRL_TYPE_VALUE_CHAN_GET,
-				      SOF_CTRL_CMD_VOLUME,
-				      true);
-
-	pm_runtime_mark_last_busy(sdev->dev);
-	err = pm_runtime_put_autosuspend(sdev->dev);
-	if (err < 0)
-		dev_err_ratelimited(sdev->dev,
-				    "error: volume put failed to idle %d\n",
-				    err);
+	if (pm_runtime_active(sdev->dev))
+		snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
+					      SOF_IPC_COMP_SET_VALUE,
+					      SOF_CTRL_TYPE_VALUE_CHAN_GET,
+					      SOF_CTRL_CMD_VOLUME,
+					      true);
+
 	return 0;
 }
 
@@ -125,37 +86,13 @@ int snd_sof_switch_get(struct snd_kcontr
 	struct soc_mixer_control *sm =
 		(struct soc_mixer_control *)kcontrol->private_value;
 	struct snd_sof_control *scontrol = sm->dobj.private;
-	struct snd_sof_dev *sdev = scontrol->sdev;
 	struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
 	unsigned int i, channels = scontrol->num_channels;
-	int err, ret;
-
-	ret = pm_runtime_get_sync(sdev->dev);
-	if (ret < 0) {
-		dev_err_ratelimited(sdev->dev,
-				    "error: switch get failed to resume %d\n",
-				    ret);
-		pm_runtime_put_noidle(sdev->dev);
-		return ret;
-	}
-
-	/* get all the mixer data from DSP */
-	snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
-				      SOF_IPC_COMP_GET_VALUE,
-				      SOF_CTRL_TYPE_VALUE_CHAN_GET,
-				      SOF_CTRL_CMD_SWITCH,
-				      false);
 
 	/* read back each channel */
 	for (i = 0; i < channels; i++)
 		ucontrol->value.integer.value[i] = cdata->chanv[i].value;
 
-	pm_runtime_mark_last_busy(sdev->dev);
-	err = pm_runtime_put_autosuspend(sdev->dev);
-	if (err < 0)
-		dev_err_ratelimited(sdev->dev,
-				    "error: switch get failed to idle %d\n",
-				    err);
 	return 0;
 }
 
@@ -168,16 +105,6 @@ int snd_sof_switch_put(struct snd_kcontr
 	struct snd_sof_dev *sdev = scontrol->sdev;
 	struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
 	unsigned int i, channels = scontrol->num_channels;
-	int ret, err;
-
-	ret = pm_runtime_get_sync(sdev->dev);
-	if (ret < 0) {
-		dev_err_ratelimited(sdev->dev,
-				    "error: switch put failed to resume %d\n",
-				    ret);
-		pm_runtime_put_noidle(sdev->dev);
-		return ret;
-	}
 
 	/* update each channel */
 	for (i = 0; i < channels; i++) {
@@ -186,18 +113,13 @@ int snd_sof_switch_put(struct snd_kcontr
 	}
 
 	/* notify DSP of mixer updates */
-	snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
-				      SOF_IPC_COMP_SET_VALUE,
-				      SOF_CTRL_TYPE_VALUE_CHAN_GET,
-				      SOF_CTRL_CMD_SWITCH,
-				      true);
-
-	pm_runtime_mark_last_busy(sdev->dev);
-	err = pm_runtime_put_autosuspend(sdev->dev);
-	if (err < 0)
-		dev_err_ratelimited(sdev->dev,
-				    "error: switch put failed to idle %d\n",
-				    err);
+	if (pm_runtime_active(sdev->dev))
+		snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
+					      SOF_IPC_COMP_SET_VALUE,
+					      SOF_CTRL_TYPE_VALUE_CHAN_GET,
+					      SOF_CTRL_CMD_SWITCH,
+					      true);
+
 	return 0;
 }
 
@@ -207,37 +129,13 @@ int snd_sof_enum_get(struct snd_kcontrol
 	struct soc_enum *se =
 		(struct soc_enum *)kcontrol->private_value;
 	struct snd_sof_control *scontrol = se->dobj.private;
-	struct snd_sof_dev *sdev = scontrol->sdev;
 	struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
 	unsigned int i, channels = scontrol->num_channels;
-	int err, ret;
-
-	ret = pm_runtime_get_sync(sdev->dev);
-	if (ret < 0) {
-		dev_err_ratelimited(sdev->dev,
-				    "error: enum get failed to resume %d\n",
-				    ret);
-		pm_runtime_put_noidle(sdev->dev);
-		return ret;
-	}
-
-	/* get all the enum data from DSP */
-	snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
-				      SOF_IPC_COMP_GET_VALUE,
-				      SOF_CTRL_TYPE_VALUE_CHAN_GET,
-				      SOF_CTRL_CMD_ENUM,
-				      false);
 
 	/* read back each channel */
 	for (i = 0; i < channels; i++)
 		ucontrol->value.enumerated.item[i] = cdata->chanv[i].value;
 
-	pm_runtime_mark_last_busy(sdev->dev);
-	err = pm_runtime_put_autosuspend(sdev->dev);
-	if (err < 0)
-		dev_err_ratelimited(sdev->dev,
-				    "error: enum get failed to idle %d\n",
-				    err);
 	return 0;
 }
 
@@ -250,16 +148,6 @@ int snd_sof_enum_put(struct snd_kcontrol
 	struct snd_sof_dev *sdev = scontrol->sdev;
 	struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
 	unsigned int i, channels = scontrol->num_channels;
-	int ret, err;
-
-	ret = pm_runtime_get_sync(sdev->dev);
-	if (ret < 0) {
-		dev_err_ratelimited(sdev->dev,
-				    "error: enum put failed to resume %d\n",
-				    ret);
-		pm_runtime_put_noidle(sdev->dev);
-		return ret;
-	}
 
 	/* update each channel */
 	for (i = 0; i < channels; i++) {
@@ -268,18 +156,13 @@ int snd_sof_enum_put(struct snd_kcontrol
 	}
 
 	/* notify DSP of enum updates */
-	snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
-				      SOF_IPC_COMP_SET_VALUE,
-				      SOF_CTRL_TYPE_VALUE_CHAN_GET,
-				      SOF_CTRL_CMD_ENUM,
-				      true);
-
-	pm_runtime_mark_last_busy(sdev->dev);
-	err = pm_runtime_put_autosuspend(sdev->dev);
-	if (err < 0)
-		dev_err_ratelimited(sdev->dev,
-				    "error: enum put failed to idle %d\n",
-				    err);
+	if (pm_runtime_active(sdev->dev))
+		snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
+					      SOF_IPC_COMP_SET_VALUE,
+					      SOF_CTRL_TYPE_VALUE_CHAN_GET,
+					      SOF_CTRL_CMD_ENUM,
+					      true);
+
 	return 0;
 }
 
@@ -293,7 +176,7 @@ int snd_sof_bytes_get(struct snd_kcontro
 	struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
 	struct sof_abi_hdr *data = cdata->data;
 	size_t size;
-	int ret, err;
+	int ret = 0;
 
 	if (be->max > sizeof(ucontrol->value.bytes.data)) {
 		dev_err_ratelimited(sdev->dev,
@@ -302,22 +185,6 @@ int snd_sof_bytes_get(struct snd_kcontro
 		return -EINVAL;
 	}
 
-	ret = pm_runtime_get_sync(sdev->dev);
-	if (ret < 0) {
-		dev_err_ratelimited(sdev->dev,
-				    "error: bytes get failed to resume %d\n",
-				    ret);
-		pm_runtime_put_noidle(sdev->dev);
-		return ret;
-	}
-
-	/* get all the binary data from DSP */
-	snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
-				      SOF_IPC_COMP_GET_DATA,
-				      SOF_CTRL_TYPE_DATA_GET,
-				      scontrol->cmd,
-				      false);
-
 	size = data->size + sizeof(*data);
 	if (size > be->max) {
 		dev_err_ratelimited(sdev->dev,
@@ -331,12 +198,6 @@ int snd_sof_bytes_get(struct snd_kcontro
 	memcpy(ucontrol->value.bytes.data, data, size);
 
 out:
-	pm_runtime_mark_last_busy(sdev->dev);
-	err = pm_runtime_put_autosuspend(sdev->dev);
-	if (err < 0)
-		dev_err_ratelimited(sdev->dev,
-				    "error: bytes get failed to idle %d\n",
-				    err);
 	return ret;
 }
 
@@ -350,7 +211,6 @@ int snd_sof_bytes_put(struct snd_kcontro
 	struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
 	struct sof_abi_hdr *data = cdata->data;
 	size_t size = data->size + sizeof(*data);
-	int ret, err;
 
 	if (be->max > sizeof(ucontrol->value.bytes.data)) {
 		dev_err_ratelimited(sdev->dev,
@@ -366,32 +226,18 @@ int snd_sof_bytes_put(struct snd_kcontro
 		return -EINVAL;
 	}
 
-	ret = pm_runtime_get_sync(sdev->dev);
-	if (ret < 0) {
-		dev_err_ratelimited(sdev->dev,
-				    "error: bytes put failed to resume %d\n",
-				    ret);
-		pm_runtime_put_noidle(sdev->dev);
-		return ret;
-	}
-
 	/* copy from kcontrol */
 	memcpy(data, ucontrol->value.bytes.data, size);
 
 	/* notify DSP of byte control updates */
-	snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
-				      SOF_IPC_COMP_SET_DATA,
-				      SOF_CTRL_TYPE_DATA_SET,
-				      scontrol->cmd,
-				      true);
-
-	pm_runtime_mark_last_busy(sdev->dev);
-	err = pm_runtime_put_autosuspend(sdev->dev);
-	if (err < 0)
-		dev_err_ratelimited(sdev->dev,
-				    "error: bytes put failed to idle %d\n",
-				    err);
-	return ret;
+	if (pm_runtime_active(sdev->dev))
+		snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
+					      SOF_IPC_COMP_SET_DATA,
+					      SOF_CTRL_TYPE_DATA_SET,
+					      scontrol->cmd,
+					      true);
+
+	return 0;
 }
 
 int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol,
@@ -406,8 +252,6 @@ int snd_sof_bytes_ext_put(struct snd_kco
 	struct snd_ctl_tlv header;
 	const struct snd_ctl_tlv __user *tlvd =
 		(const struct snd_ctl_tlv __user *)binary_data;
-	int ret;
-	int err;
 
 	/*
 	 * The beginning of bytes data contains a header from where
@@ -453,30 +297,15 @@ int snd_sof_bytes_ext_put(struct snd_kco
 		return -EINVAL;
 	}
 
-	ret = pm_runtime_get_sync(sdev->dev);
-	if (ret < 0) {
-		dev_err_ratelimited(sdev->dev,
-				    "error: bytes_ext put failed to resume %d\n",
-				    ret);
-		pm_runtime_put_noidle(sdev->dev);
-		return ret;
-	}
-
 	/* notify DSP of byte control updates */
-	snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
-				      SOF_IPC_COMP_SET_DATA,
-				      SOF_CTRL_TYPE_DATA_SET,
-				      scontrol->cmd,
-				      true);
-
-	pm_runtime_mark_last_busy(sdev->dev);
-	err = pm_runtime_put_autosuspend(sdev->dev);
-	if (err < 0)
-		dev_err_ratelimited(sdev->dev,
-				    "error: bytes_ext put failed to idle %d\n",
-				    err);
+	if (pm_runtime_active(sdev->dev))
+		snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
+					      SOF_IPC_COMP_SET_DATA,
+					      SOF_CTRL_TYPE_DATA_SET,
+					      scontrol->cmd,
+					      true);
 
-	return ret;
+	return 0;
 }
 
 int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol,
@@ -492,17 +321,7 @@ int snd_sof_bytes_ext_get(struct snd_kco
 	struct snd_ctl_tlv __user *tlvd =
 		(struct snd_ctl_tlv __user *)binary_data;
 	int data_size;
-	int err;
-	int ret;
-
-	ret = pm_runtime_get_sync(sdev->dev);
-	if (ret < 0) {
-		dev_err_ratelimited(sdev->dev,
-				    "error: bytes_ext get failed to resume %d\n",
-				    ret);
-		pm_runtime_put_noidle(sdev->dev);
-		return ret;
-	}
+	int ret = 0;
 
 	/*
 	 * Decrement the limit by ext bytes header size to
@@ -514,13 +333,6 @@ int snd_sof_bytes_ext_get(struct snd_kco
 	cdata->data->magic = SOF_ABI_MAGIC;
 	cdata->data->abi = SOF_ABI_VERSION;
 
-	/* get all the component data from DSP */
-	ret = snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
-					    SOF_IPC_COMP_GET_DATA,
-					    SOF_CTRL_TYPE_DATA_GET,
-					    scontrol->cmd,
-					    false);
-
 	/* Prevent read of other kernel data or possibly corrupt response */
 	data_size = cdata->data->size + sizeof(const struct sof_abi_hdr);
 
@@ -543,11 +355,5 @@ int snd_sof_bytes_ext_get(struct snd_kco
 		ret = -EFAULT;
 
 out:
-	pm_runtime_mark_last_busy(sdev->dev);
-	err = pm_runtime_put_autosuspend(sdev->dev);
-	if (err < 0)
-		dev_err_ratelimited(sdev->dev,
-				    "error: bytes_ext get failed to idle %d\n",
-				    err);
 	return ret;
 }
diff -Naurp linux-source-5.2-orig/sound/soc/sof/intel/hda-dai.c linux-source-5.2/sound/soc/sof/intel/hda-dai.c
--- linux-source-5.2-orig/sound/soc/sof/intel/hda-dai.c	2019-08-16 04:11:12.000000000 -0400
+++ linux-source-5.2/sound/soc/sof/intel/hda-dai.c	2019-09-18 22:17:59.327619433 -0400
@@ -30,62 +30,84 @@ struct hda_pipe_params {
 };
 
 /*
- * Unlike GP dma, there is a set of stream registers in hda controller
- * to control the link dma channels. Each register controls one link
- * dma channel and the relation is fixed. To make sure FW uses correct
- * link dma channels, host allocates stream registers and sends the
- * corresponding link dma channels to FW to allocate link dma channel
- *
- * FIXME: this API is abused in the sense that tx_num and rx_num are
- * passed as arguments, not returned. We need to find a better way to
- * retrieve the stream tag allocated for the link DMA
+ * This function checks if the host dma channel corresponding
+ * to the link DMA stream_tag argument is assigned to one
+ * of the FEs connected to the BE DAI.
  */
-static int hda_link_dma_get_channels(struct snd_soc_dai *dai,
-				     unsigned int *tx_num,
-				     unsigned int *tx_slot,
-				     unsigned int *rx_num,
-				     unsigned int *rx_slot)
+static bool hda_check_fes(struct snd_soc_pcm_runtime *rtd,
+			  int dir, int stream_tag)
 {
-	struct hdac_bus *bus;
-	struct hdac_ext_stream *stream;
-	struct snd_pcm_substream substream;
-	struct snd_sof_dev *sdev =
-		snd_soc_component_get_drvdata(dai->component);
+	struct snd_pcm_substream *fe_substream;
+	struct hdac_stream *fe_hstream;
+	struct snd_soc_dpcm *dpcm;
+
+	for_each_dpcm_fe(rtd, dir, dpcm) {
+		fe_substream = snd_soc_dpcm_get_substream(dpcm->fe, dir);
+		fe_hstream = fe_substream->runtime->private_data;
+		if (fe_hstream->stream_tag == stream_tag)
+			return true;
+	}
 
-	bus = sof_to_bus(sdev);
+	return false;
+}
 
-	memset(&substream, 0, sizeof(substream));
-	if (*tx_num == 1) {
-		substream.stream = SNDRV_PCM_STREAM_PLAYBACK;
-		stream = snd_hdac_ext_stream_assign(bus, &substream,
-						    HDAC_EXT_STREAM_TYPE_LINK);
-		if (!stream) {
-			dev_err(bus->dev, "error: failed to find a free hda ext stream for playback");
-			return -EBUSY;
-		}
+static struct hdac_ext_stream *
+	hda_link_stream_assign(struct hdac_bus *bus,
+			       struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct sof_intel_hda_stream *hda_stream;
+	struct hdac_ext_stream *res = NULL;
+	struct hdac_stream *stream = NULL;
 
-		snd_soc_dai_set_dma_data(dai, &substream, stream);
-		*tx_slot = hdac_stream(stream)->stream_tag - 1;
+	int stream_dir = substream->stream;
 
-		dev_dbg(bus->dev, "link dma channel %d for playback", *tx_slot);
+	if (!bus->ppcap) {
+		dev_err(bus->dev, "stream type not supported\n");
+		return NULL;
 	}
 
-	if (*rx_num == 1) {
-		substream.stream = SNDRV_PCM_STREAM_CAPTURE;
-		stream = snd_hdac_ext_stream_assign(bus, &substream,
-						    HDAC_EXT_STREAM_TYPE_LINK);
-		if (!stream) {
-			dev_err(bus->dev, "error: failed to find a free hda ext stream for capture");
-			return -EBUSY;
+	list_for_each_entry(stream, &bus->stream_list, list) {
+		struct hdac_ext_stream *hstream =
+			stream_to_hdac_ext_stream(stream);
+		if (stream->direction != substream->stream)
+			continue;
+
+		hda_stream = hstream_to_sof_hda_stream(hstream);
+
+		/* check if available */
+		if (!hstream->link_locked) {
+			if (stream->opened) {
+				/*
+				 * check if the stream tag matches the stream
+				 * tag of one of the connected FEs
+				 */
+				if (hda_check_fes(rtd, stream_dir,
+						  stream->stream_tag)) {
+					res = hstream;
+					break;
+				}
+			} else {
+				res = hstream;
+				break;
+			}
 		}
+	}
 
-		snd_soc_dai_set_dma_data(dai, &substream, stream);
-		*rx_slot = hdac_stream(stream)->stream_tag - 1;
-
-		dev_dbg(bus->dev, "link dma channel %d for capture", *rx_slot);
+	if (res) {
+		/*
+		 * Decouple host and link DMA. The decoupled flag
+		 * is updated in snd_hdac_ext_stream_decouple().
+		 */
+		if (!res->decoupled)
+			snd_hdac_ext_stream_decouple(bus, res, true);
+		spin_lock_irq(&bus->reg_lock);
+		res->link_locked = 1;
+		res->link_substream = substream;
+		spin_unlock_irq(&bus->reg_lock);
 	}
 
-	return 0;
+	return res;
 }
 
 static int hda_link_dma_params(struct hdac_ext_stream *stream,
@@ -122,6 +144,51 @@ static int hda_link_dma_params(struct hd
 	return 0;
 }
 
+/* Send DAI_CONFIG IPC to the DAI that matches the dai_name and direction */
+static int hda_link_config_ipc(struct sof_intel_hda_stream *hda_stream,
+			       const char *dai_name, int channel, int dir)
+{
+	struct sof_ipc_dai_config *config;
+	struct snd_sof_dai *sof_dai;
+	struct sof_ipc_reply reply;
+	int ret = 0;
+
+	list_for_each_entry(sof_dai, &hda_stream->sdev->dai_list, list) {
+		if (!sof_dai->cpu_dai_name)
+			continue;
+
+		if (!strcmp(dai_name, sof_dai->cpu_dai_name) &&
+		    dir == sof_dai->comp_dai.direction) {
+			config = sof_dai->dai_config;
+
+			if (!config) {
+				dev_err(hda_stream->sdev->dev,
+					"error: no config for DAI %s\n",
+					sof_dai->name);
+				return -EINVAL;
+			}
+
+			/* update config with stream tag */
+			config->hda.link_dma_ch = channel;
+
+			/* send IPC */
+			ret = sof_ipc_tx_message(hda_stream->sdev->ipc,
+						 config->hdr.cmd,
+						 config,
+						 config->hdr.size,
+						 &reply, sizeof(reply));
+
+			if (ret < 0)
+				dev_err(hda_stream->sdev->dev,
+					"error: failed to set dai config for %s\n",
+					sof_dai->name);
+			return ret;
+		}
+	}
+
+	return -EINVAL;
+}
+
 static int hda_link_hw_params(struct snd_pcm_substream *substream,
 			      struct snd_pcm_hw_params *params,
 			      struct snd_soc_dai *dai)
@@ -135,20 +202,31 @@ static int hda_link_hw_params(struct snd
 	struct hda_pipe_params p_params = {0};
 	struct hdac_ext_link *link;
 	int stream_tag;
+	int ret;
 
-	link_dev = snd_soc_dai_get_dma_data(dai, substream);
+	link_dev = hda_link_stream_assign(bus, substream);
+	if (!link_dev)
+		return -EBUSY;
+
+	stream_tag = hdac_stream(link_dev)->stream_tag;
+
+	hda_stream = hstream_to_sof_hda_stream(link_dev);
+
+	/* update the DSP with the new tag */
+	ret = hda_link_config_ipc(hda_stream, dai->name, stream_tag - 1,
+				  substream->stream);
+	if (ret < 0)
+		return ret;
+
+	snd_soc_dai_set_dma_data(dai, substream, (void *)link_dev);
 
-	hda_stream = container_of(link_dev, struct sof_intel_hda_stream,
-				  hda_stream);
 	hda_stream->hw_params_upon_resume = 0;
 
 	link = snd_hdac_ext_bus_get_link(bus, codec_dai->component->name);
 	if (!link)
 		return -EINVAL;
 
-	stream_tag = hdac_stream(link_dev)->stream_tag;
-
-	/* set the stream tag in the codec dai dma params  */
+	/* set the stream tag in the codec dai dma params */
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 		snd_soc_dai_set_tdm_slot(codec_dai, stream_tag, 0, 0, 0);
 	else
@@ -181,8 +259,7 @@ static int hda_link_pcm_prepare(struct s
 	struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
 	int stream = substream->stream;
 
-	hda_stream = container_of(link_dev, struct sof_intel_hda_stream,
-				  hda_stream);
+	hda_stream = hstream_to_sof_hda_stream(link_dev);
 
 	/* setup hw_params again only if resuming from system suspend */
 	if (!hda_stream->hw_params_upon_resume)
@@ -199,8 +276,24 @@ static int hda_link_pcm_trigger(struct s
 {
 	struct hdac_ext_stream *link_dev =
 				snd_soc_dai_get_dma_data(dai, substream);
+	struct sof_intel_hda_stream *hda_stream;
+	struct snd_soc_pcm_runtime *rtd;
+	struct hdac_ext_link *link;
+	struct hdac_stream *hstream;
+	struct hdac_bus *bus;
+	int stream_tag;
 	int ret;
 
+	hstream = substream->runtime->private_data;
+	bus = hstream->bus;
+	rtd = snd_pcm_substream_chip(substream);
+
+	link = snd_hdac_ext_bus_get_link(bus, rtd->codec_dai->component->name);
+	if (!link)
+		return -EINVAL;
+
+	hda_stream = hstream_to_sof_hda_stream(link_dev);
+
 	dev_dbg(dai->dev, "In %s cmd=%d\n", __func__, cmd);
 	switch (cmd) {
 	case SNDRV_PCM_TRIGGER_RESUME:
@@ -217,8 +310,22 @@ static int hda_link_pcm_trigger(struct s
 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
 		snd_hdac_ext_link_stream_start(link_dev);
 		break;
-	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 	case SNDRV_PCM_TRIGGER_SUSPEND:
+		/*
+		 * clear and release link DMA channel. It will be assigned when
+		 * hw_params is set up again after resume.
+		 */
+		ret = hda_link_config_ipc(hda_stream, dai->name,
+					  DMA_CHAN_INVALID, substream->stream);
+		if (ret < 0)
+			return ret;
+		stream_tag = hdac_stream(link_dev)->stream_tag;
+		snd_hdac_ext_link_clear_stream_id(link, stream_tag);
+		snd_hdac_ext_stream_release(link_dev,
+					    HDAC_EXT_STREAM_TYPE_LINK);
+
+		/* fallthrough */
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 	case SNDRV_PCM_TRIGGER_STOP:
 		snd_hdac_ext_link_stream_clear(link_dev);
 		break;
@@ -228,62 +335,38 @@ static int hda_link_pcm_trigger(struct s
 	return 0;
 }
 
-/*
- * FIXME: This API is also abused since it's used for two purposes.
- * when the substream argument is NULL this function is used for cleanups
- * that aren't necessarily required, and called explicitly by handling
- * ASoC core structures, which is not recommended.
- * This part will be reworked in follow-up patches.
- */
 static int hda_link_hw_free(struct snd_pcm_substream *substream,
 			    struct snd_soc_dai *dai)
 {
-	const char *name;
 	unsigned int stream_tag;
+	struct sof_intel_hda_stream *hda_stream;
 	struct hdac_bus *bus;
 	struct hdac_ext_link *link;
 	struct hdac_stream *hstream;
-	struct hdac_ext_stream *stream;
 	struct snd_soc_pcm_runtime *rtd;
 	struct hdac_ext_stream *link_dev;
-	struct snd_pcm_substream pcm_substream;
+	int ret;
 
-	memset(&pcm_substream, 0, sizeof(pcm_substream));
-	if (substream) {
-		hstream = substream->runtime->private_data;
-		bus = hstream->bus;
-		rtd = snd_pcm_substream_chip(substream);
-		link_dev = snd_soc_dai_get_dma_data(dai, substream);
-		snd_hdac_ext_stream_decouple(bus, link_dev, false);
-		name = rtd->codec_dai->component->name;
-		link = snd_hdac_ext_bus_get_link(bus, name);
-		if (!link)
-			return -EINVAL;
-
-		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-			stream_tag = hdac_stream(link_dev)->stream_tag;
-			snd_hdac_ext_link_clear_stream_id(link, stream_tag);
-		}
+	hstream = substream->runtime->private_data;
+	bus = hstream->bus;
+	rtd = snd_pcm_substream_chip(substream);
+	link_dev = snd_soc_dai_get_dma_data(dai, substream);
+	hda_stream = hstream_to_sof_hda_stream(link_dev);
 
-		link_dev->link_prepared = 0;
-	} else {
-		/* release all hda streams when dai link is unloaded */
-		pcm_substream.stream = SNDRV_PCM_STREAM_PLAYBACK;
-		stream = snd_soc_dai_get_dma_data(dai, &pcm_substream);
-		if (stream) {
-			snd_soc_dai_set_dma_data(dai, &pcm_substream, NULL);
-			snd_hdac_ext_stream_release(stream,
-						    HDAC_EXT_STREAM_TYPE_LINK);
-		}
+	/* free the link DMA channel in the FW */
+	ret = hda_link_config_ipc(hda_stream, dai->name, DMA_CHAN_INVALID,
+				  substream->stream);
+	if (ret < 0)
+		return ret;
 
-		pcm_substream.stream = SNDRV_PCM_STREAM_CAPTURE;
-		stream = snd_soc_dai_get_dma_data(dai, &pcm_substream);
-		if (stream) {
-			snd_soc_dai_set_dma_data(dai, &pcm_substream, NULL);
-			snd_hdac_ext_stream_release(stream,
-						    HDAC_EXT_STREAM_TYPE_LINK);
-		}
-	}
+	link = snd_hdac_ext_bus_get_link(bus, rtd->codec_dai->component->name);
+	if (!link)
+		return -EINVAL;
+
+	stream_tag = hdac_stream(link_dev)->stream_tag;
+	snd_hdac_ext_link_clear_stream_id(link, stream_tag);
+	snd_hdac_ext_stream_release(link_dev, HDAC_EXT_STREAM_TYPE_LINK);
+	link_dev->link_prepared = 0;
 
 	return 0;
 }
@@ -293,7 +376,6 @@ static const struct snd_soc_dai_ops hda_
 	.hw_free = hda_link_hw_free,
 	.trigger = hda_link_pcm_trigger,
 	.prepare = hda_link_pcm_prepare,
-	.get_channel_map = hda_link_dma_get_channels,
 };
 #endif
 
diff -Naurp linux-source-5.2-orig/sound/soc/sof/intel/hda-dsp.c linux-source-5.2/sound/soc/sof/intel/hda-dsp.c
--- linux-source-5.2-orig/sound/soc/sof/intel/hda-dsp.c	2019-08-16 04:11:12.000000000 -0400
+++ linux-source-5.2/sound/soc/sof/intel/hda-dsp.c	2019-09-18 22:18:13.739172971 -0400
@@ -454,18 +454,45 @@ int hda_dsp_suspend(struct snd_sof_dev *
 	return 0;
 }
 
-void hda_dsp_set_hw_params_upon_resume(struct snd_sof_dev *sdev)
+int hda_dsp_set_hw_params_upon_resume(struct snd_sof_dev *sdev)
 {
 	struct hdac_bus *bus = sof_to_bus(sdev);
 	struct sof_intel_hda_stream *hda_stream;
 	struct hdac_ext_stream *stream;
 	struct hdac_stream *s;
 
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
+	struct snd_soc_pcm_runtime *rtd;
+	struct hdac_ext_link *link;
+	const char *name;
+#endif
+	int stream_tag;
+
 	/* set internal flag for BE */
 	list_for_each_entry(s, &bus->stream_list, list) {
 		stream = stream_to_hdac_ext_stream(s);
 		hda_stream = container_of(stream, struct sof_intel_hda_stream,
 					  hda_stream);
 		hda_stream->hw_params_upon_resume = 1;
+		stream_tag = hdac_stream(stream)->stream_tag;
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
+		/*
+		 * clear and release stream. This should already be taken care
+		 * for running streams when the SUSPEND trigger is called.
+		 * But paused streams do not get suspended, so this needs to be
+		 * done explicitly during suspend.
+		 */
+		if (stream->link_substream) {
+			rtd = snd_pcm_substream_chip(stream->link_substream);
+			name = rtd->codec_dai->component->name;
+			link = snd_hdac_ext_bus_get_link(bus, name);
+			if (!link)
+				return -EINVAL;
+			snd_hdac_ext_link_clear_stream_id(link, stream_tag);
+			snd_hdac_ext_stream_release(stream,
+						    HDAC_EXT_STREAM_TYPE_LINK);
+		}
+#endif
 	}
+	return 0;
 }
diff -Naurp linux-source-5.2-orig/sound/soc/sof/intel/hda.h linux-source-5.2/sound/soc/sof/intel/hda.h
--- linux-source-5.2-orig/sound/soc/sof/intel/hda.h	2019-08-16 04:11:12.000000000 -0400
+++ linux-source-5.2/sound/soc/sof/intel/hda.h	2019-09-18 22:18:37.726615756 -0400
@@ -407,11 +407,15 @@ static inline struct hda_bus *sof_to_hbu
 }
 
 struct sof_intel_hda_stream {
+	struct snd_sof_dev *sdev;
 	struct hdac_ext_stream hda_stream;
 	struct sof_intel_stream stream;
 	int hw_params_upon_resume; /* set up hw_params upon resume */
 };
 
+#define hstream_to_sof_hda_stream(hstream) \
+	container_of(hstream, struct sof_intel_hda_stream, hda_stream)
+
 #define bus_to_sof_hda(bus) \
 	container_of(bus, struct sof_intel_hda_dev, hbus.core)
 
@@ -444,7 +448,7 @@ int hda_dsp_suspend(struct snd_sof_dev *
 int hda_dsp_resume(struct snd_sof_dev *sdev);
 int hda_dsp_runtime_suspend(struct snd_sof_dev *sdev, int state);
 int hda_dsp_runtime_resume(struct snd_sof_dev *sdev);
-void hda_dsp_set_hw_params_upon_resume(struct snd_sof_dev *sdev);
+int hda_dsp_set_hw_params_upon_resume(struct snd_sof_dev *sdev);
 void hda_dsp_dump_skl(struct snd_sof_dev *sdev, u32 flags);
 void hda_dsp_dump(struct snd_sof_dev *sdev, u32 flags);
 void hda_ipc_dump(struct snd_sof_dev *sdev);
diff -Naurp linux-source-5.2-orig/sound/soc/sof/intel/hda-stream.c linux-source-5.2/sound/soc/sof/intel/hda-stream.c
--- linux-source-5.2-orig/sound/soc/sof/intel/hda-stream.c	2019-08-16 04:11:12.000000000 -0400
+++ linux-source-5.2/sound/soc/sof/intel/hda-stream.c	2019-09-18 22:18:37.726615756 -0400
@@ -564,6 +564,8 @@ int hda_dsp_stream_init(struct snd_sof_d
 		if (!hda_stream)
 			return -ENOMEM;
 
+		hda_stream->sdev = sdev;
+
 		stream = &hda_stream->hda_stream;
 
 		stream->pphc_addr = sdev->bar[HDA_DSP_PP_BAR] +
@@ -617,6 +619,8 @@ int hda_dsp_stream_init(struct snd_sof_d
 		if (!hda_stream)
 			return -ENOMEM;
 
+		hda_stream->sdev = sdev;
+
 		stream = &hda_stream->hda_stream;
 
 		/* we always have DSP support */
diff -Naurp linux-source-5.2-orig/sound/soc/sof/ops.h linux-source-5.2/sound/soc/sof/ops.h
--- linux-source-5.2-orig/sound/soc/sof/ops.h	2019-08-16 04:11:12.000000000 -0400
+++ linux-source-5.2/sound/soc/sof/ops.h	2019-09-18 22:18:13.739172971 -0400
@@ -134,10 +134,11 @@ static inline int snd_sof_dsp_runtime_su
 	return 0;
 }
 
-static inline void snd_sof_dsp_hw_params_upon_resume(struct snd_sof_dev *sdev)
+static inline int snd_sof_dsp_hw_params_upon_resume(struct snd_sof_dev *sdev)
 {
 	if (sof_ops(sdev)->set_hw_params_upon_resume)
-		sof_ops(sdev)->set_hw_params_upon_resume(sdev);
+		return sof_ops(sdev)->set_hw_params_upon_resume(sdev);
+	return 0;
 }
 
 static inline int snd_sof_dsp_set_clk(struct snd_sof_dev *sdev, u32 freq)
diff -Naurp linux-source-5.2-orig/sound/soc/sof/pm.c linux-source-5.2/sound/soc/sof/pm.c
--- linux-source-5.2-orig/sound/soc/sof/pm.c	2019-08-16 04:11:12.000000000 -0400
+++ linux-source-5.2/sound/soc/sof/pm.c	2019-09-18 22:18:13.739172971 -0400
@@ -153,6 +153,15 @@ static int sof_restore_pipelines(struct
 			continue;
 		}
 
+		/*
+		 * The link DMA channel would be invalidated for running
+		 * streams but not for streams that were in the PAUSED
+		 * state during suspend. So invalidate it here before setting
+		 * the dai config in the DSP.
+		 */
+		if (config->type == SOF_DAI_INTEL_HDA)
+			config->hda.link_dma_ch = DMA_CHAN_INVALID;
+
 		ret = sof_ipc_tx_message(sdev->ipc,
 					 config->hdr.cmd, config,
 					 config->hdr.size,
@@ -204,7 +213,7 @@ static int sof_send_pm_ipc(struct snd_so
 				 sizeof(pm_ctx), &reply, sizeof(reply));
 }
 
-static void sof_set_hw_params_upon_resume(struct snd_sof_dev *sdev)
+static int sof_set_hw_params_upon_resume(struct snd_sof_dev *sdev)
 {
 	struct snd_pcm_substream *substream;
 	struct snd_sof_pcm *spcm;
@@ -229,7 +238,7 @@ static void sof_set_hw_params_upon_resum
 	}
 
 	/* set internal flag for BE */
-	snd_sof_dsp_hw_params_upon_resume(sdev);
+	return snd_sof_dsp_hw_params_upon_resume(sdev);
 }
 
 #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_DEBUGFS_CACHE)
@@ -333,8 +342,15 @@ static int sof_suspend(struct device *de
 	snd_sof_release_trace(sdev);
 
 	/* set restore_stream for all streams during system suspend */
-	if (!runtime_suspend)
-		sof_set_hw_params_upon_resume(sdev);
+	if (!runtime_suspend) {
+		ret = sof_set_hw_params_upon_resume(sdev);
+		if (ret < 0) {
+			dev_err(sdev->dev,
+				"error: setting hw_params flag during suspend %d\n",
+				ret);
+			return ret;
+		}
+	}
 
 #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_DEBUGFS_CACHE)
 	/* cache debugfs contents during runtime suspend */
@@ -343,11 +359,20 @@ static int sof_suspend(struct device *de
 #endif
 	/* notify DSP of upcoming power down */
 	ret = sof_send_pm_ipc(sdev, SOF_IPC_PM_CTX_SAVE);
-	if (ret < 0) {
+	if (ret == -EBUSY || ret == -EAGAIN) {
+		/*
+		 * runtime PM has logic to handle -EBUSY/-EAGAIN so
+		 * pass these errors up
+		 */
 		dev_err(sdev->dev,
 			"error: ctx_save ipc error during suspend %d\n",
 			ret);
 		return ret;
+	} else if (ret < 0) {
+		/* FW in unexpected state, continue to power down */
+		dev_warn(sdev->dev,
+			 "ctx_save ipc error %d, proceeding with suspend\n",
+			 ret);
 	}
 
 	/* power down all DSP cores */
diff -Naurp linux-source-5.2-orig/sound/soc/sof/sof-priv.h linux-source-5.2/sound/soc/sof/sof-priv.h
--- linux-source-5.2-orig/sound/soc/sof/sof-priv.h	2019-08-16 04:11:12.000000000 -0400
+++ linux-source-5.2/sound/soc/sof/sof-priv.h	2019-09-18 22:18:13.743172859 -0400
@@ -56,6 +56,8 @@
 #define SOF_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | \
 	SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_FLOAT)
 
+#define DMA_CHAN_INVALID	0xFFFFFFFF
+
 struct snd_sof_dev;
 struct snd_sof_ipc_msg;
 struct snd_sof_ipc;
@@ -166,7 +168,7 @@ struct snd_sof_dsp_ops {
 	int (*runtime_suspend)(struct snd_sof_dev *sof_dev,
 			       int state); /* optional */
 	int (*runtime_resume)(struct snd_sof_dev *sof_dev); /* optional */
-	void (*set_hw_params_upon_resume)(struct snd_sof_dev *sdev); /* optional */
+	int (*set_hw_params_upon_resume)(struct snd_sof_dev *sdev); /* optional */
 
 	/* DSP clocking */
 	int (*set_clk)(struct snd_sof_dev *sof_dev, u32 freq); /* optional */
@@ -331,6 +333,7 @@ struct snd_sof_route {
 struct snd_sof_dai {
 	struct snd_sof_dev *sdev;
 	const char *name;
+	const char *cpu_dai_name;
 
 	struct sof_ipc_comp_dai comp_dai;
 	struct sof_ipc_dai_config *dai_config;
diff -Naurp linux-source-5.2-orig/sound/soc/sof/topology.c linux-source-5.2/sound/soc/sof/topology.c
--- linux-source-5.2-orig/sound/soc/sof/topology.c	2019-08-16 04:11:12.000000000 -0400
+++ linux-source-5.2/sound/soc/sof/topology.c	2019-09-18 22:18:22.970932678 -0400
@@ -2340,6 +2340,9 @@ static int sof_set_dai_config(struct snd
 			if (!dai->dai_config)
 				return -ENOMEM;
 
+			/* set cpu_dai_name */
+			dai->cpu_dai_name = link->cpu_dai_name;
+
 			found = 1;
 		}
 	}
@@ -2568,9 +2571,7 @@ err:
  */
 static int sof_link_hda_process(struct snd_sof_dev *sdev,
 				struct snd_soc_dai_link *link,
-				struct sof_ipc_dai_config *config,
-				int tx_slot,
-				int rx_slot)
+				struct sof_ipc_dai_config *config)
 {
 	struct sof_ipc_reply reply;
 	u32 size = sizeof(*config);
@@ -2583,27 +2584,18 @@ static int sof_link_hda_process(struct s
 			continue;
 
 		if (strcmp(link->name, sof_dai->name) == 0) {
-			if (sof_dai->comp_dai.direction ==
-			    SNDRV_PCM_STREAM_PLAYBACK) {
-				if (!link->dpcm_playback)
-					return -EINVAL;
-
-				config->hda.link_dma_ch = tx_slot;
-			} else {
-				if (!link->dpcm_capture)
-					return -EINVAL;
-
-				config->hda.link_dma_ch = rx_slot;
-			}
-
 			config->dai_index = sof_dai->comp_dai.dai_index;
 			found = 1;
 
+			config->hda.link_dma_ch = DMA_CHAN_INVALID;
+
 			/* save config in dai component */
 			sof_dai->dai_config = kmemdup(config, size, GFP_KERNEL);
 			if (!sof_dai->dai_config)
 				return -ENOMEM;
 
+			sof_dai->cpu_dai_name = link->cpu_dai_name;
+
 			/* send message to DSP */
 			ret = sof_ipc_tx_message(sdev->ipc,
 						 config->hdr.cmd, config, size,
@@ -2643,10 +2635,6 @@ static int sof_link_hda_load(struct snd_
 	struct snd_soc_tplg_private *private = &cfg->priv;
 	struct snd_soc_dai *dai;
 	u32 size = sizeof(*config);
-	u32 tx_num = 0;
-	u32 tx_slot = 0;
-	u32 rx_num = 0;
-	u32 rx_slot = 0;
 	int ret;
 
 	/* init IPC */
@@ -2672,22 +2660,7 @@ static int sof_link_hda_load(struct snd_
 		return -EINVAL;
 	}
 
-	if (link->dpcm_playback)
-		tx_num = 1;
-
-	if (link->dpcm_capture)
-		rx_num = 1;
-
-	ret = snd_soc_dai_get_channel_map(dai, &tx_num, &tx_slot,
-					  &rx_num, &rx_slot);
-	if (ret < 0) {
-		dev_err(sdev->dev, "error: failed to get dma channel for HDA%d\n",
-			config->dai_index);
-
-		return ret;
-	}
-
-	ret = sof_link_hda_process(sdev, link, config, tx_slot, rx_slot);
+	ret = sof_link_hda_process(sdev, link, config);
 	if (ret < 0)
 		dev_err(sdev->dev, "error: failed to process hda dai link %s",
 			link->name);
@@ -2814,17 +2787,6 @@ static int sof_link_hda_unload(struct sn
 		return -EINVAL;
 	}
 
-	/*
-	 * FIXME: this call to hw_free is mainly to release the link DMA ID.
-	 * This is abusing the API and handling SOC internals is not
-	 * recommended. This part will be reworked.
-	 */
-	if (dai->driver->ops->hw_free)
-		ret = dai->driver->ops->hw_free(NULL, dai);
-	if (ret < 0)
-		dev_err(sdev->dev, "error: failed to free hda resource for %s\n",
-			link->name);
-
 	return ret;
 }
 
@@ -2998,6 +2960,49 @@ err:
 	return ret;
 }
 
+/* Function to set the initial value of SOF kcontrols.
+ * The value will be stored in scontrol->control_data
+ */
+static int snd_sof_cache_kcontrol_val(struct snd_sof_dev *sdev)
+{
+	struct snd_sof_control *scontrol = NULL;
+	int ipc_cmd, ctrl_type;
+	int ret = 0;
+
+	list_for_each_entry(scontrol, &sdev->kcontrol_list, list) {
+
+		/* notify DSP of kcontrol values */
+		switch (scontrol->cmd) {
+		case SOF_CTRL_CMD_VOLUME:
+		case SOF_CTRL_CMD_ENUM:
+		case SOF_CTRL_CMD_SWITCH:
+			ipc_cmd = SOF_IPC_COMP_GET_VALUE;
+			ctrl_type = SOF_CTRL_TYPE_VALUE_CHAN_GET;
+			break;
+		case SOF_CTRL_CMD_BINARY:
+			ipc_cmd = SOF_IPC_COMP_GET_DATA;
+			ctrl_type = SOF_CTRL_TYPE_DATA_GET;
+			break;
+		default:
+			dev_err(sdev->dev,
+				"error: Invalid scontrol->cmd: %d\n",
+				scontrol->cmd);
+			return -EINVAL;
+		}
+		ret = snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
+						    ipc_cmd, ctrl_type,
+						    scontrol->cmd,
+						    false);
+		if (ret < 0) {
+			dev_warn(sdev->dev,
+				"error: kcontrol value get for widget: %d\n",
+				scontrol->comp_id);
+		}
+	}
+
+	return ret;
+}
+
 int snd_sof_complete_pipeline(struct snd_sof_dev *sdev,
 			      struct snd_sof_widget *swidget)
 {
@@ -3041,6 +3046,11 @@ static void sof_complete(struct snd_soc_
 			break;
 		}
 	}
+	/*
+	 * cache initial values of SOF kcontrols by reading DSP value over
+	 * IPC. It may be overwritten by alsa-mixer after booting up
+	 */
+	snd_sof_cache_kcontrol_val(sdev);
 }
 
 /* manifest - optional to inform component of manifest */
# Generic SOF selections
CONFIG_SND_SOC_SOF_TOPLEVEL=y
CONFIG_SND_SOC_SOF_PCI=m
CONFIG_SND_SOC_SOF_ACPI=m

# debug options
CONFIG_SND_SOC_SOF_DEBUG=y
CONFIG_SND_SOC_SOF_DEBUG_VERBOSE_IPC=y
CONFIG_SND_SOC_SOF_DEBUG_ENABLE_DEBUGFS_CACHE=y
CONFIG_SND_SOC_SOF_DEBUG_ENABLE_FIRMWARE_TRACE=y
CONFIG_SND_SOC_SOF_DEBUG_IPC_FLOOD_TEST=y

# SOF Intel platform drivers
CONFIG_SND_SOC_SOF_INTEL_TOPLEVEL=y
CONFIG_SND_SOC_SOF_BAYTRAIL_SUPPORT=y
CONFIG_SND_SOC_SOF_HASWELL_SUPPORT=y
CONFIG_SND_SOC_SOF_BROADWELL_SUPPORT=y
CONFIG_SND_SOC_SOF_MERRIFIELD_SUPPORT=y
CONFIG_SND_SOC_SOF_SKYLAKE_SUPPORT=y
CONFIG_SND_SOC_SOF_APOLLOLAKE_SUPPORT=y
CONFIG_SND_SOC_SOF_KABYLAKE_SUPPORT=y
CONFIG_SND_SOC_SOF_GEMINILAKE_SUPPORT=y
CONFIG_SND_SOC_SOF_CANNONLAKE_SUPPORT=y
CONFIG_SND_SOC_SOF_COFFEELAKE_SUPPORT=y
CONFIG_SND_SOC_SOF_ICELAKE_SUPPORT=y
CONFIG_SND_SOC_SOF_COMETLAKE_LP_SUPPORT=y
CONFIG_SND_SOC_SOF_COMETLAKE_H_SUPPORT=y
CONFIG_SND_SOC_SOF_TIGERLAKE_SUPPORT=y
CONFIG_SND_SOC_SOF_ELKHARTLAKE_SUPPORT=y

# Intel machine drivers
CONFIG_SND_SOC_INTEL_HASWELL_MACH=m
CONFIG_SND_SOC_INTEL_BDW_RT5677_MACH=m
CONFIG_SND_SOC_INTEL_BROADWELL_MACH=m
CONFIG_SND_SOC_INTEL_BYTCR_RT5640_MACH=m
CONFIG_SND_SOC_INTEL_BYTCR_RT5651_MACH=m
CONFIG_SND_SOC_INTEL_CHT_BSW_RT5672_MACH=m
CONFIG_SND_SOC_INTEL_CHT_BSW_RT5645_MACH=m
CONFIG_SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH=m
CONFIG_SND_SOC_INTEL_CHT_BSW_NAU8824_MACH=m
CONFIG_SND_SOC_INTEL_BYT_CHT_DA7213_MACH=m
CONFIG_SND_SOC_INTEL_BYT_CHT_ES8316_MACH=m
CONFIG_SND_SOC_INTEL_BYT_CHT_CX2072X_MACH=m
CONFIG_SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH=m
CONFIG_SND_SOC_INTEL_BXT_RT298_MACH=m
CONFIG_SND_SOC_INTEL_BXT_PCM512x_MACH=m
CONFIG_SND_SOC_INTEL_BXT_WM8804_MACH=m
CONFIG_SND_SOC_INTEL_GLK_RT5682_MAX98357A_MACH=m
CONFIG_SND_SOC_INTEL_SOF_RT5682_MACH=m
CONFIG_SND_SOC_INTEL_CML_LP_DA7219_MAX98357A_MACH=m
CONFIG_SND_SOC_INTEL_TGL_RT1308_MACH=m
CONFIG_SND_SOC_INTEL_SOUNDWIRE_RT700_MACH=m
CONFIG_SND_SOC_INTEL_SOUNDWIRE_RT711_RT1308_RT715_MACH=m
CONFIG_SND_HDA_INTEL=m

# enable HDaudio support in SST
CONFIG_SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC=y


# enable HDaudio in SOF. this might be redundant with sof-mach-driver-defconfig
CONFIG_SND_SOC_SOF_HDA_LINK=y
CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC=y

# machine driver for HDaudio support
CONFIG_SND_SOC_INTEL_SKL_HDA_DSP_GENERIC_MACH=m

# HDaudio configs
CONFIG_SND_HDA_INPUT_BEEP=y
CONFIG_SND_HDA_PATCH_LOADER=y
CONFIG_SND_HDA_CODEC_REALTEK=m
CONFIG_SND_HDA_CODEC_ANALOG=m
CONFIG_SND_HDA_CODEC_SIGMATEL=m
CONFIG_SND_HDA_CODEC_VIA=m
CONFIG_SND_HDA_CODEC_HDMI=m
CONFIG_SND_HDA_CODEC_CIRRUS=m
CONFIG_SND_HDA_CODEC_CONEXANT=m
CONFIG_SND_HDA_CODEC_CA0110=m
CONFIG_SND_HDA_CODEC_CA0132=m
CONFIG_SND_HDA_CODEC_CMEDIA=m
CONFIG_SND_HDA_CODEC_SI3054=m
CONFIG_SND_HDA_GENERIC=m

--- End Message ---
--- Begin Message ---
Source: linux
Source-Version: 5.3.7-1

We believe that the bug you reported is fixed in the latest version of
linux, which is due to be installed in the Debian FTP archive.

A summary of the changes between this version and the previous one is
attached.

Thank you for reporting the bug, which will now be closed.  If you
have further comments please address them to 940726@bugs.debian.org,
and the maintainer will reopen the bug report if appropriate.

Debian distribution maintenance software
pp.
Salvatore Bonaccorso <carnil@debian.org> (supplier of updated linux package)

(This message was generated automatically at their request; if you
believe that there is a problem with it please contact the archive
administrators by mailing ftpmaster@ftp-master.debian.org)


-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512

Format: 1.8
Date: Sun, 20 Oct 2019 00:56:32 +0200
Binary: linux-doc linux-doc-5.3 linux-headers-5.3.0-1-common linux-source linux-source-5.3 linux-support-5.3.0-1
Source: linux
Architecture: all source
Version: 5.3.7-1
Distribution: unstable
Urgency: medium
Maintainer: Debian Kernel Team <debian-kernel@lists.debian.org>
Changed-By: Salvatore Bonaccorso <carnil@debian.org>
Closes: 935945 940530 940726
Description: 
 linux-doc  - Linux kernel specific documentation (meta-package)
 linux-doc-5.3 - Linux kernel specific documentation for version 5.3
 linux-headers-5.3.0-1-common - Common header files for Linux 5.3.0-1
 linux-source - Linux kernel source (meta-package)
 linux-source-5.3 - Linux kernel source for version 5.3 with Debian patches
 linux-support-5.3.0-1 - Support files for Linux 5.3
Changes:
 linux (5.3.7-1) unstable; urgency=medium
 .
   * New upstream stable update:
     https://www.kernel.org/pub/linux/kernel/v5.x/ChangeLog-5.3.3
     https://www.kernel.org/pub/linux/kernel/v5.x/ChangeLog-5.3.4
     - mISDN: enforce CAP_NET_RAW for raw sockets (CVE-2019-17055)
     - appletalk: enforce CAP_NET_RAW for raw sockets (CVE-2019-17054)
     - ax25: enforce CAP_NET_RAW for raw sockets (CVE-2019-17052)
     - ieee802154: enforce CAP_NET_RAW for raw sockets (CVE-2019-17053)
     - nfc: enforce CAP_NET_RAW for raw sockets (CVE-2019-17056)
     https://www.kernel.org/pub/linux/kernel/v5.x/ChangeLog-5.3.5
     https://www.kernel.org/pub/linux/kernel/v5.x/ChangeLog-5.3.6
     - nl80211: validate beacon head (CVE-2019-16746)
     https://www.kernel.org/pub/linux/kernel/v5.x/ChangeLog-5.3.7
 .
   [ Aurelien Jarno ]
   * [riscv64] Enable SOC_SIFIVE. Do not select CLK_SIFIVE,
     CLK_SIFIVE_FU540_PRCI, SIFIVE_PLIC, SERIAL_SIFIVE and
     SERIAL_SIFIVE_CONSOLE as they are selected by SOC_SIFIVE.
   * [riscv64] Install DTBS using dtbs_install target.
   * [riscv64] Enable SPI_SIFIVE.
   * [riscv64] Enable SERIAL_EARLYCON_RISCV_SBI.
   * [riscv64] Enable MMC, MMC_SPI.
   * [riscv64] udeb: Add mmc-core-modules and mmc-modules.
   * [riscv64] Fix memblock reservation for device tree blob.
   * [riscv64] Clear load reservations while restoring hart contexts.
 .
   [ Ben Hutchings ]
   * [mips*] Revert "Only define MAX_PHYSMEM_BITS on Loongson-3"
   * KEYS: Re-enable SECONDARY_TRUSTED_KEYRING, dropped in 5.2.6-1 by
     mis-merge (Closes: #935945)
 .
   [ John Paul Adrian Glaubitz ]
   * [m68k] Enable CONFIG_CRYPTO_MANAGER_DISABLE_TESTS
   * [hppa] Enable CONFIG_CRYPTO_MANAGER_DISABLE_TESTS
   * [sh4] Enable CONFIG_CRYPTO_MANAGER_DISABLE_TESTS
 .
   [ Salvatore Bonaccorso ]
   * RDMA/cxgb4: Do not dma memory off of the stack (CVE-2019-17075)
   * ath6kl: fix a NULL-ptr-deref bug in ath6kl_usb_alloc_urb_from_pipe()
     (CVE-2019-15098)
 .
   [ Romain Perier ]
   * [armel/rpi] Enable CONFIG_BRCMFMAC_SDIO (Closes: #940530)
 .
   [ Héctor Orón Martínez ]
   * [x86] Enable ASoC: SOF sound driver (Closes: #940726)
Checksums-Sha1: 
 dd39fa2e65c62ec7c17add4d1578bbbff0429bd3 197683 linux_5.3.7-1.dsc
 45d9f10d69dceefafb5e9d1e29ad3e6e58bb96ff 112780220 linux_5.3.7.orig.tar.xz
 ca48db4fb3ff8e40daf4b8dbdfaa598e92f673b5 1161944 linux_5.3.7-1.debian.tar.xz
 71a522cf99e7872587c484cb2722bc2a08c4c5ad 48127 linux_5.3.7-1_source.buildinfo
 45a3592576cd34f2c145fec7cf078ee303eb0314 23082928 linux-doc-5.3_5.3.7-1_all.deb
 5b297e8a819ae1e44c9c3ab779b492c25d76b642 916 linux-doc_5.3.7-1_all.deb
 86212659324eaf57c5a595e3b5efda1705ced0f4 8241652 linux-headers-5.3.0-1-common_5.3.7-1_all.deb
 5d01961c534b93f080166348857e291c466eeca8 111565576 linux-source-5.3_5.3.7-1_all.deb
 b1f295b76ee1f3036bef1e2e250ba22142fa0a09 912 linux-source_5.3.7-1_all.deb
 f8d8f14538bfcb93dbc2ddda3b4595d5c3c1a90d 83344 linux-support-5.3.0-1_5.3.7-1_all.deb
 ad6e953567931073c23451652ceb12cec45789cc 53027 linux_5.3.7-1_all.buildinfo
Checksums-Sha256: 
 f725294a5feb858139b883e06173869822e13f3946416d0c2c59c40b05e34348 197683 linux_5.3.7-1.dsc
 8a020a6770a87aa332be1f2cbf419b99b6c33bb578a27a91bea1011ec7ea860a 112780220 linux_5.3.7.orig.tar.xz
 ce04f29431a3a8fb6cb17f6c2cdce6201130c99c24cd7e1ba0198f4334352de6 1161944 linux_5.3.7-1.debian.tar.xz
 b48149c4befeda3f341dbe046efdb49e83434779a4109a7646d5984aa9fe8fcf 48127 linux_5.3.7-1_source.buildinfo
 b10f9939021844b5556f84fba3713aa830020892d857c452e407b76aa7f7334d 23082928 linux-doc-5.3_5.3.7-1_all.deb
 9d05cb498d530c8aab18d70784fdda212a16a90c5be5bed87d4dca2abd7a3c20 916 linux-doc_5.3.7-1_all.deb
 8308c4de8557bfc5f5aacd4103b5c0a40e57c3f9e5f22a11d9e6681d813e6cae 8241652 linux-headers-5.3.0-1-common_5.3.7-1_all.deb
 6ad099c99fe4b90dd65f0e75270fbca1e80ac4964a3a41afd58ab5f436d95f3e 111565576 linux-source-5.3_5.3.7-1_all.deb
 fbf230a975ff9578713066afc2a2ae1382ae47ad1b3045a042d7ff9ab33b30a1 912 linux-source_5.3.7-1_all.deb
 e38b36003e5de24817cf02b59cd7a125cfebbb0f09629087f25df1416fca8e3f 83344 linux-support-5.3.0-1_5.3.7-1_all.deb
 8b7276033768df6531c0394b758319a9784261121b4382be1ca16bd47f77fbe8 53027 linux_5.3.7-1_all.buildinfo
Files: 
 224ae06dcf067d07244098801e5e6e50 197683 kernel optional linux_5.3.7-1.dsc
 0c287d56961660bf8c8e22a552ce3f24 112780220 kernel optional linux_5.3.7.orig.tar.xz
 d0372e61ee173e29920e571ca37298e3 1161944 kernel optional linux_5.3.7-1.debian.tar.xz
 20071d3bfe471705adc486dced8e64a5 48127 kernel optional linux_5.3.7-1_source.buildinfo
 8bbb3c27f0b062f027cf82197f25b165 23082928 doc optional linux-doc-5.3_5.3.7-1_all.deb
 f09b6031409c84585c75241f9c429aa4 916 doc optional linux-doc_5.3.7-1_all.deb
 b6cbc2cee8cbe6fa16d6cbecc6c8d909 8241652 kernel optional linux-headers-5.3.0-1-common_5.3.7-1_all.deb
 1f29f7ab89f6eac21cc948101b2a105d 111565576 kernel optional linux-source-5.3_5.3.7-1_all.deb
 190dbee7f69bd31fe636929d1debb758 912 kernel optional linux-source_5.3.7-1_all.deb
 8c4918bc0b4c324acc9a4c5cff3c06f9 83344 devel optional linux-support-5.3.0-1_5.3.7-1_all.deb
 de597c307bb08c7012faab98c841aa31 53027 kernel optional linux_5.3.7-1_all.buildinfo

-----BEGIN PGP SIGNATURE-----

iQKmBAEBCgCQFiEERkRAmAjBceBVMd3uBUy48xNDz0QFAl2sqVNfFIAAAAAALgAo
aXNzdWVyLWZwckBub3RhdGlvbnMub3BlbnBncC5maWZ0aGhvcnNlbWFuLm5ldDQ2
NDQ0MDk4MDhDMTcxRTA1NTMxRERFRTA1NENCOEYzMTM0M0NGNDQSHGNhcm5pbEBk
ZWJpYW4ub3JnAAoJEAVMuPMTQ89ETysP/0JnTG3SxUF0Es5xIzyVPWUlD233kVFe
O9kP29f7nZW0ltFptAcdX6vTUmnPCjhVMbIwL2Y97EAxgK5mkttG/6AVPsy2cL50
3inrvppu1UiBJ1wgdZ6+XXlOIfbithTkjqtZxt1rx72xJfnPeGFSek/3729yMewP
+sG+VLVDIymx338KEYueq85XckxWtbYZ5z+eJfSaHum/cjSj1Xai6yCVK2+2Adlt
6H849i1E4Pqz/ua8BWMlBChIKxlp2mt5eQgglgI5h6seQOs01gdSIqo5SnWH1UBS
XpGV8OLyjAVAyMopNqhZXcO6H+Oj2PdW35MQH37Yn0tqgWA3M+U+ceRJmwr4i12r
pL444KJgTsrMJaNecEoNjLzd9GwZFc6MYQEczT7mRmswghKsd1ItEFCjYLCfOU+F
2HhzNixrXUa5ZaqkN1U51Lvm9rXRS+PL5zCUopg2mC3/KdgvmM/C8tbiUSrDBQSv
g/MzzlrMOjUujbwQGnv+h4jEiBT2fd9mdM2gU9DN1+U3pc/t9RA0eP/cC6++WrKx
yTr0DAgaz/TIrs8aVsP7XIJhCrsIf8RUBiT1M8n4Sz2i3p1bQymz67Ww/7zRnzDb
+svbF+DmZZ8VaqddSY0uP3spyMiM/5PgWtVqx/c+neUVbPKuYx31OkaYwFziJ5gp
UoFliekSmX2C
=jbPc
-----END PGP SIGNATURE-----

--- End Message ---

Reply to: