From c15e0d77949bdbbc05d76736428aca2609d0e129 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 17 Apr 2026 12:30:11 +0300 Subject: [PATCH 1/4] ASoC: SOF: Intel: hda: Fold mlink enumeration into hda_dsp_ctrl_init_chip() Move the hda_bus_ml_init() call from hda_init_caps() into hda_dsp_ctrl_init_chip(), right after the HDA controller reset has been de-asserted and unsolicited responses have been accepted. hda_dsp_ctrl_init_chip() already calls hda_bus_ml_reset_losidv() at the end of its sequence to clear the stream-to-link mapping. On first boot this call was a no-op because the multi-link list had not yet been populated: hda_bus_ml_init() only runs later in hda_init_caps(). Enumerating the links inside init_chip() makes the LOSIDV reset effective on first boot as well, without adding a second reset call from the probe path. hda_bus_ml_init() now returns early when the hlink_list is already populated, so the subsequent invocations from the D3 resume path (hda_resume() -> hda_dsp_ctrl_init_chip(false)) are no-ops. Signed-off-by: Peter Ujfalusi --- sound/soc/sof/intel/hda-ctrl.c | 8 ++++++++ sound/soc/sof/intel/hda-mlink.c | 4 ++++ sound/soc/sof/intel/hda.c | 2 -- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/intel/hda-ctrl.c b/sound/soc/sof/intel/hda-ctrl.c index 8332d4bda5581f..a9ead78d3fcbf0 100644 --- a/sound/soc/sof/intel/hda-ctrl.c +++ b/sound/soc/sof/intel/hda-ctrl.c @@ -223,6 +223,14 @@ int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev, bool detect_codec) /* Accept unsolicited responses */ snd_hdac_chip_updatel(bus, GCTL, AZX_GCTL_UNSOL, AZX_GCTL_UNSOL); + /* Perform a one-time enumeration of the Multi-Link capability */ + ret = hda_bus_ml_init(bus); + if (ret < 0) { + dev_err(sdev->dev, "%s: failed to enumerate multi-links\n", + __func__); + goto err; + } + if (detect_codec) hda_codec_detect_mask(sdev); diff --git a/sound/soc/sof/intel/hda-mlink.c b/sound/soc/sof/intel/hda-mlink.c index 92314e3b568aa0..ca8551befdb53e 100644 --- a/sound/soc/sof/intel/hda-mlink.c +++ b/sound/soc/sof/intel/hda-mlink.c @@ -432,6 +432,10 @@ int hda_bus_ml_init(struct hdac_bus *bus) if (!bus->mlcap) return 0; + /* Enumeration is a one time operation, skip if already done */ + if (!list_empty(&bus->hlink_list)) + return 0; + link_count = readl(bus->mlcap + AZX_REG_ML_MLCD) + 1; dev_dbg(bus->dev, "HDAudio Multi-Link count: %d\n", link_count); diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index b3d61d973ce40b..14166d17e1c577 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -625,8 +625,6 @@ static int hda_init_caps(struct snd_sof_dev *sdev) return ret; } - hda_bus_ml_init(bus); - /* Skip SoundWire if it is not supported */ if (!(interface_mask & BIT(SOF_DAI_INTEL_ALH))) goto skip_soundwire; From 3225a6f47eeebdbdfd372508f9ff0d826d90eb7c Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 17 Apr 2026 11:39:30 +0300 Subject: [PATCH 2/4] ASoC: SOF: Intel: hda: Keep non-alt mlinks powered at probe on ACE2+ Drop the hda_bus_ml_put_all() call at the end of hda_init_caps(). On multi-link (mlink) capable platforms the non-alternate links (HDaudio and iDisp) are powered on by hardware when CRST# is de-asserted (LCTL.SPA = 1) and their ref_count is pre-charged to 1 in hda_ml_alloc_h2link() to match this state. The put_all call immediately dropped that reference and toggled LCTL.SPA back to 0, relying on the first stream open to power the link up again. On ACE2+ platforms this redundant SPA 1->0->1 toggle at probe leaves the Processing Pipe Capability (PPLC) Linear Link Position counters in a state where they do not advance on the first stream after boot. The counters only start working after the first full runtime suspend/resume cycle, which includes a CRST# assert/deassert that fully resets the PPC AON block. Keep the non-alt links powered from CRST# de-assert through first use. System suspend still powers them down via hda_bus_ml_suspend(), and resume relies on CRST# de-assert to bring them back up, so no other path is affected. Signed-off-by: Peter Ujfalusi --- sound/soc/sof/intel/hda.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 14166d17e1c577..b5fa6ecb8eadb6 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -668,8 +668,6 @@ static int hda_init_caps(struct snd_sof_dev *sdev) if (!HDA_IDISP_CODEC(bus->codec_mask)) hda_codec_i915_display_power(sdev, false); - hda_bus_ml_put_all(bus); - return 0; } From da4a638ed065f84b607d15e4402f8c2a8293c079 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 22 Apr 2026 09:55:43 +0300 Subject: [PATCH 3/4] ASoC: SOF: Intel: hda: Remove unused hda_bus_ml_put_all() The helper became unused after probe no longer drops all non-alt links, so remove the dead API and implementation. Signed-off-by: Peter Ujfalusi --- include/sound/hda-mlink.h | 2 -- sound/soc/sof/intel/hda-mlink.c | 13 ------------- 2 files changed, 15 deletions(-) diff --git a/include/sound/hda-mlink.h b/include/sound/hda-mlink.h index fed69998c93f7f..d9789b048c6106 100644 --- a/include/sound/hda-mlink.h +++ b/include/sound/hda-mlink.h @@ -49,7 +49,6 @@ int hdac_bus_eml_sdw_set_lsdiid(struct hdac_bus *bus, int sublink, int dev_num); int hdac_bus_eml_sdw_map_stream_ch(struct hdac_bus *bus, int sublink, int y, int channel_mask, int stream_id, int dir); -void hda_bus_ml_put_all(struct hdac_bus *bus); void hda_bus_ml_reset_losidv(struct hdac_bus *bus); int hda_bus_ml_resume(struct hdac_bus *bus); int hda_bus_ml_suspend(struct hdac_bus *bus); @@ -169,7 +168,6 @@ hdac_bus_eml_sdw_map_stream_ch(struct hdac_bus *bus, int sublink, int y, return 0; } -static inline void hda_bus_ml_put_all(struct hdac_bus *bus) { } static inline void hda_bus_ml_reset_losidv(struct hdac_bus *bus) { } static inline int hda_bus_ml_resume(struct hdac_bus *bus) { return 0; } static inline int hda_bus_ml_suspend(struct hdac_bus *bus) { return 0; } diff --git a/sound/soc/sof/intel/hda-mlink.c b/sound/soc/sof/intel/hda-mlink.c index ca8551befdb53e..e0107cbd06e65e 100644 --- a/sound/soc/sof/intel/hda-mlink.c +++ b/sound/soc/sof/intel/hda-mlink.c @@ -884,19 +884,6 @@ int hdac_bus_eml_sdw_map_stream_ch(struct hdac_bus *bus, int sublink, int y, return 0; } EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_map_stream_ch, "SND_SOC_SOF_HDA_MLINK"); -void hda_bus_ml_put_all(struct hdac_bus *bus) -{ - struct hdac_ext_link *hlink; - - list_for_each_entry(hlink, &bus->hlink_list, list) { - struct hdac_ext2_link *h2link = hdac_ext_link_to_ext2(hlink); - - if (!h2link->alt) - snd_hdac_ext_bus_link_put(bus, hlink); - } -} -EXPORT_SYMBOL_NS(hda_bus_ml_put_all, "SND_SOC_SOF_HDA_MLINK"); - void hda_bus_ml_reset_losidv(struct hdac_bus *bus) { struct hdac_ext_link *hlink; From d0bfef8fdc8c0578ab934685538b6476deaaa8cb Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Mon, 20 Apr 2026 17:55:48 +0300 Subject: [PATCH 4/4] ASoC: SOF: Intel: hda: Avoid ACE2+ link DMA stream allocation hazards On ACE2+ platforms the link DMA stream allocator must avoid two hardware errata in mlink-capable systems: - Concurrent (cross-direction) hazard: when SoundWire shares a physical link DMA stream index with HDaudio, iDisp or UAOL across the two directions, the LLP and timestamp values for the affected stream are wrong. SSP and DMIC are not affected because every DMA request from those links carries one sample block. - Sequential (playback only) hazard: once a HDaudio or iDisp link has used a playback stream index, that index cannot drive any non HDA/iDisp link in the same direction until the next controller reset (CRST#). Track the active link type per direction in two masks (one for SoundWire, one for HDA/iDisp/UAOL) and the persistent set of playback stream indices touched by HDA/iDisp in a third mask. The link DMA allocator skips streams that would violate either rule. Streams are released from the active masks when the stream is released; all masks are cleared in hda_dsp_ctrl_init_chip() because the CRST# performed there clears the hardware state as well. A new helper hda_bus_ml_link_get_type() returns the link type from the existing extended link descriptor so the SOF allocator can tell SoundWire, HDA/iDisp and UAOL apart without duplicating the parsing. The implementation is generic. On platforms older than ACE2 every link is reported as HDA, only the sequential mask is ever set and it has no effect because no other link types are present, so behavior is unchanged. Signed-off-by: Peter Ujfalusi --- include/sound/hda-mlink.h | 21 +++++++++ sound/soc/sof/intel/hda-ctrl.c | 11 +++++ sound/soc/sof/intel/hda-dai-ops.c | 76 ++++++++++++++++++++++++++++--- sound/soc/sof/intel/hda-dai.c | 2 +- sound/soc/sof/intel/hda-mlink.c | 18 ++++++++ sound/soc/sof/intel/hda.h | 26 ++++++++++- 6 files changed, 146 insertions(+), 8 deletions(-) diff --git a/include/sound/hda-mlink.h b/include/sound/hda-mlink.h index d9789b048c6106..ba35f03576b9da 100644 --- a/include/sound/hda-mlink.h +++ b/include/sound/hda-mlink.h @@ -9,6 +9,22 @@ struct hdac_bus; struct hdac_ext_link; +/** + * enum hda_bus_ml_link_type - mlink link type, used by SOF link DMA + * allocator constraints (see struct sof_intel_hda_dev). + * + * @HDA_BUS_ML_LINK_HDA: non-alt link, i.e. HDA codec or iDisp + * @HDA_BUS_ML_LINK_SDW: alt link, SoundWire + * @HDA_BUS_ML_LINK_UAOL: alt link, USB Audio Offload + * @HDA_BUS_ML_LINK_OTHER: alt link, SSP or DMIC + */ +enum hda_bus_ml_link_type { + HDA_BUS_ML_LINK_HDA, + HDA_BUS_ML_LINK_SDW, + HDA_BUS_ML_LINK_UAOL, + HDA_BUS_ML_LINK_OTHER, +}; + #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_MLINK) int hda_bus_ml_init(struct hdac_bus *bus); @@ -53,6 +69,8 @@ void hda_bus_ml_reset_losidv(struct hdac_bus *bus); int hda_bus_ml_resume(struct hdac_bus *bus); int hda_bus_ml_suspend(struct hdac_bus *bus); +enum hda_bus_ml_link_type hda_bus_ml_link_get_type(struct hdac_ext_link *hlink); + struct hdac_ext_link *hdac_bus_eml_ssp_get_hlink(struct hdac_bus *bus); struct hdac_ext_link *hdac_bus_eml_dmic_get_hlink(struct hdac_bus *bus); struct hdac_ext_link *hdac_bus_eml_sdw_get_hlink(struct hdac_bus *bus); @@ -172,6 +190,9 @@ static inline void hda_bus_ml_reset_losidv(struct hdac_bus *bus) { } static inline int hda_bus_ml_resume(struct hdac_bus *bus) { return 0; } static inline int hda_bus_ml_suspend(struct hdac_bus *bus) { return 0; } +static inline enum hda_bus_ml_link_type +hda_bus_ml_link_get_type(struct hdac_ext_link *hlink) { return HDA_BUS_ML_LINK_HDA; } + static inline struct hdac_ext_link * hdac_bus_eml_ssp_get_hlink(struct hdac_bus *bus) { return NULL; } diff --git a/sound/soc/sof/intel/hda-ctrl.c b/sound/soc/sof/intel/hda-ctrl.c index a9ead78d3fcbf0..aeb34310eebd61 100644 --- a/sound/soc/sof/intel/hda-ctrl.c +++ b/sound/soc/sof/intel/hda-ctrl.c @@ -186,6 +186,7 @@ EXPORT_SYMBOL_NS(hda_dsp_ctrl_clock_power_gating, "SND_SOC_SOF_INTEL_HDA_COMMON" int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev, bool detect_codec) { struct hdac_bus *bus = sof_to_bus(sdev); + struct sof_intel_hda_dev *sof_hda = bus_to_sof_hda(bus); struct hdac_stream *stream; int sd_offset, ret = 0; u32 gctl; @@ -193,6 +194,16 @@ int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev, bool detect_codec) if (bus->chip_init) return 0; + /* + * The controller reset clears the ACE2+ link DMA stream allocation + * constraints; reset the masks to reflect this. + */ + memset(sof_hda->link_dma_active_sdw_mask, 0, + sizeof(sof_hda->link_dma_active_sdw_mask)); + memset(sof_hda->link_dma_active_multi_mask, 0, + sizeof(sof_hda->link_dma_active_multi_mask)); + sof_hda->link_dma_out_hda_used_mask = 0; + hda_codec_set_codec_wakeup(sdev, true); hda_dsp_ctrl_misc_clock_gating(sdev, false); diff --git a/sound/soc/sof/intel/hda-dai-ops.c b/sound/soc/sof/intel/hda-dai-ops.c index b2c55955996294..f0be42048db33c 100644 --- a/sound/soc/sof/intel/hda-dai-ops.c +++ b/sound/soc/sof/intel/hda-dai-ops.c @@ -20,7 +20,7 @@ /* These ops are only applicable for the HDA DAI's in their current form */ #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_LINK) /* - * This function checks if the host dma channel corresponding + * This function checks if the host DMA stream corresponding * to the link DMA stream_tag argument is assigned to one * of the FEs connected to the BE DAI. */ @@ -42,23 +42,53 @@ static bool hda_check_fes(struct snd_soc_pcm_runtime *rtd, } static struct hdac_ext_stream * -hda_link_stream_assign(struct hdac_bus *bus, struct snd_pcm_substream *substream) +hda_link_stream_assign(struct hdac_bus *bus, struct snd_pcm_substream *substream, + enum hda_bus_ml_link_type link_type) { struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct sof_intel_hda_dev *sof_hda = bus_to_sof_hda(bus); struct sof_intel_hda_stream *hda_stream; const struct sof_intel_dsp_desc *chip; struct snd_sof_dev *sdev; struct hdac_ext_stream *res = NULL; struct hdac_stream *hstream = NULL; - int stream_dir = substream->stream; + bool is_multi = link_type == HDA_BUS_ML_LINK_HDA || link_type == HDA_BUS_ML_LINK_UAOL; + bool is_play = stream_dir == SNDRV_PCM_STREAM_PLAYBACK; + bool is_sdw = link_type == HDA_BUS_ML_LINK_SDW; + bool is_hda = link_type == HDA_BUS_ML_LINK_HDA; + u32 concur_block_mask = 0; + u32 seq_block_mask = 0; + unsigned int stream_idx; if (!bus->ppcap) { dev_err(bus->dev, "stream type not supported\n"); return NULL; } + /* + * On ACE2+ the link DMA stream allocator must avoid two HW errata, + * see the comment on struct sof_intel_hda_dev. + * + * - Concurrent cross-direction: SoundWire conflicts with HDA, iDisp + * and UAOL on the same physical stream index; SSP and DMIC are safe. + * - Sequential playback: a stream index previously used by an HDA/iDisp + * link cannot drive any non-HDA/iDisp link in the same direction + * until the next controller reset. + * + * The masks are protected by bus->reg_lock; sample them inside the + * lock together with the stream walk to keep the decision atomic + * with concurrent allocations and releases. + */ guard(spinlock_irq)(&bus->reg_lock); + + if (is_sdw) + concur_block_mask = sof_hda->link_dma_active_multi_mask[!stream_dir]; + else if (is_multi) + concur_block_mask = sof_hda->link_dma_active_sdw_mask[!stream_dir]; + if (is_play && !is_hda) + seq_block_mask = sof_hda->link_dma_out_hda_used_mask; + list_for_each_entry(hstream, &bus->stream_list, list) { struct hdac_ext_stream *hext_stream = stream_to_hdac_ext_stream(hstream); @@ -69,6 +99,12 @@ hda_link_stream_assign(struct hdac_bus *bus, struct snd_pcm_substream *substream sdev = hda_stream->sdev; chip = get_chip_info(sdev->pdata); + stream_idx = hstream->stream_tag - 1; + + /* skip streams blocked by the ACE2+ allocator constraints */ + if ((concur_block_mask | seq_block_mask) & BIT(stream_idx)) + continue; + /* check if link is available */ if (!hext_stream->link_locked) { /* @@ -95,7 +131,7 @@ hda_link_stream_assign(struct hdac_bus *bus, struct snd_pcm_substream *substream /* * This must be a hostless stream. - * So reserve the host DMA channel. + * So reserve the host DMA stream. */ hda_stream->host_reserved = 1; break; @@ -109,6 +145,16 @@ hda_link_stream_assign(struct hdac_bus *bus, struct snd_pcm_substream *substream res->link_locked = 1; res->link_substream = substream; + + stream_idx = res->hstream.stream_tag - 1; + if (is_sdw) + sof_hda->link_dma_active_sdw_mask[stream_dir] |= BIT(stream_idx); + else if (is_multi) + sof_hda->link_dma_active_multi_mask[stream_dir] |= BIT(stream_idx); + + /* persistent OUT HDA/iDisp shadow, cleared only on CRST# */ + if (is_hda && is_play) + sof_hda->link_dma_out_hda_used_mask |= BIT(stream_idx); } return res; @@ -143,11 +189,13 @@ static struct hdac_ext_stream *hda_ipc4_get_hext_stream(struct snd_sof_dev *sdev static struct hdac_ext_stream *hda_assign_hext_stream(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai, - struct snd_pcm_substream *substream) + struct snd_pcm_substream *substream, + struct hdac_ext_link *hlink) { struct hdac_ext_stream *hext_stream; + enum hda_bus_ml_link_type link_type = hda_bus_ml_link_get_type(hlink); - hext_stream = hda_link_stream_assign(sof_to_bus(sdev), substream); + hext_stream = hda_link_stream_assign(sof_to_bus(sdev), substream, link_type); if (!hext_stream) return NULL; @@ -160,6 +208,22 @@ static void hda_release_hext_stream(struct snd_sof_dev *sdev, struct snd_soc_dai struct snd_pcm_substream *substream) { struct hdac_ext_stream *hext_stream = hda_get_hext_stream(sdev, cpu_dai, substream); + struct sof_intel_hda_dev *sof_hda = sdev->pdata->hw_pdata; + struct hdac_bus *bus = sof_to_bus(sdev); + int dir = substream->stream; + unsigned int stream_idx = hext_stream->hstream.stream_tag - 1; + + /* + * Drop the stream index from the per-direction active concurrency masks. + * The two masks are mutually exclusive for a given stream/direction + * (and a stream of the SSP/DMIC kind appears in neither), so a blind + * clear of both is safe and lets us avoid having to remember the + * link type at allocation time. + */ + scoped_guard(spinlock_irq, &bus->reg_lock) { + sof_hda->link_dma_active_sdw_mask[dir] &= ~BIT(stream_idx); + sof_hda->link_dma_active_multi_mask[dir] &= ~BIT(stream_idx); + } snd_soc_dai_set_dma_data(cpu_dai, substream, NULL); snd_hdac_ext_stream_release(hext_stream, HDAC_EXT_STREAM_TYPE_LINK); diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c index 15faedeec16d78..bb44d4f8a4da04 100644 --- a/sound/soc/sof/intel/hda-dai.c +++ b/sound/soc/sof/intel/hda-dai.c @@ -188,7 +188,7 @@ static int hda_link_dma_hw_params(struct snd_pcm_substream *substream, if (!hext_stream) { if (ops->assign_hext_stream) - hext_stream = ops->assign_hext_stream(sdev, cpu_dai, substream); + hext_stream = ops->assign_hext_stream(sdev, cpu_dai, substream, hlink); } if (!hext_stream) diff --git a/sound/soc/sof/intel/hda-mlink.c b/sound/soc/sof/intel/hda-mlink.c index e0107cbd06e65e..6f02fb5b70cedc 100644 --- a/sound/soc/sof/intel/hda-mlink.c +++ b/sound/soc/sof/intel/hda-mlink.c @@ -894,6 +894,24 @@ void hda_bus_ml_reset_losidv(struct hdac_bus *bus) } EXPORT_SYMBOL_NS(hda_bus_ml_reset_losidv, "SND_SOC_SOF_HDA_MLINK"); +enum hda_bus_ml_link_type hda_bus_ml_link_get_type(struct hdac_ext_link *hlink) +{ + struct hdac_ext2_link *h2link = hdac_ext_link_to_ext2(hlink); + + if (!h2link->alt) + return HDA_BUS_ML_LINK_HDA; + + switch (h2link->elid) { + case AZX_REG_ML_LEPTR_ID_SDW: + return HDA_BUS_ML_LINK_SDW; + case AZX_REG_ML_LEPTR_ID_INTEL_UAOL: + return HDA_BUS_ML_LINK_UAOL; + default: + return HDA_BUS_ML_LINK_OTHER; + } +} +EXPORT_SYMBOL_NS(hda_bus_ml_link_get_type, "SND_SOC_SOF_HDA_MLINK"); + int hda_bus_ml_resume(struct hdac_bus *bus) { struct hdac_ext_link *hlink; diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 3f0966477ace21..8a7c9a10e51c04 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -523,6 +523,29 @@ struct sof_intel_hda_dev { /* the maximum number of streams (playback + capture) supported */ u32 stream_max; + /* + * ACE2+ link DMA stream allocation constraints (stream index = + * stream_tag - 1, shared between input and output directions). All + * masks are cleared by hda_dsp_ctrl_init_chip() on controller reset + * (CRST#). + * + * - Concurrent (cross-direction) constraint: a SoundWire stream and + * a HDA/iDisp/UAOL stream cannot share a physical stream index + * across directions, the resulting LLP/timestamp values are wrong. + * link_dma_active_sdw_mask and link_dma_active_multi_mask + * (indexed by SNDRV_PCM_STREAM_*) track currently allocated + * streams per direction in each of the conflicting groups; SSP + * and DMIC do not participate. Bits are cleared on stream release. + * + * - Sequential (playback only) constraint: once a HDA/iDisp link + * has used a playback stream index, that index cannot drive a + * non-HDA/iDisp link in the same direction until the next CRST#. + * link_dma_out_hda_used_mask records this. + */ + u32 link_dma_active_sdw_mask[SNDRV_PCM_STREAM_LAST + 1]; + u32 link_dma_active_multi_mask[SNDRV_PCM_STREAM_LAST + 1]; + u32 link_dma_out_hda_used_mask; + /* PM related */ bool l1_disabled;/* is DMI link L1 disabled? */ @@ -1030,7 +1053,8 @@ struct hda_dai_widget_dma_ops { struct snd_pcm_substream *substream); struct hdac_ext_stream *(*assign_hext_stream)(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai, - struct snd_pcm_substream *substream); + struct snd_pcm_substream *substream, + struct hdac_ext_link *hlink); void (*release_hext_stream)(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai, struct snd_pcm_substream *substream); void (*setup_hext_stream)(struct snd_sof_dev *sdev, struct hdac_ext_stream *hext_stream,