aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>2023-05-12 12:46:06 -0500
committerMark Brown <broonie@kernel.org>2023-05-15 10:20:09 +0900
commit7430dea49410de3d154fb87f931d079a0a643b1a (patch)
treefa1217177d0a10dfe727191d9decffef1abc2788
parentf63550e2b165208a2f382afcaf5551df9569e1d4 (diff)
downloadlinux-7430dea49410de3d154fb87f931d079a0a643b1a.tar.gz
ASoC: SOF: Intel: hda-mlink: fix sublink refcounting
In hindsight it was a very bad idea to use the same refcount for Extended and 'legacy' HDaudio multi-links. The existing solution only powers-up the first sublink, which causes SoundWire and SSP tests to fail when more than one DAI is used concurrently. Solving this problem requires per-sublink refcounting, as suggested in this patch. The existing refcounting remains for 'legacy' HdAudio links, mainly to avoid changing the obscure programming sequence in snd_hdac_ext_bus_link_put(). Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com Reviewed-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com Reviewed-by: Bard Liao <yung-chuan.liao@linux.intel.com Link: https://lore.kernel.org/r/20230512174611.84372-2-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown <broonie@kernel.org
-rw-r--r--sound/soc/sof/intel/hda-mlink.c24
1 files changed, 19 insertions, 5 deletions
diff --git a/sound/soc/sof/intel/hda-mlink.c b/sound/soc/sof/intel/hda-mlink.c
index 775582ab749418..6d0145c30afe44 100644
--- a/sound/soc/sof/intel/hda-mlink.c
+++ b/sound/soc/sof/intel/hda-mlink.c
@@ -19,6 +19,9 @@
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_MLINK)
+/* worst-case number of sublinks is used for sublink refcount array allocation only */
+#define HDAML_MAX_SUBLINKS (AZX_ML_LCTL_CPA_SHIFT - AZX_ML_LCTL_SPA_SHIFT)
+
/**
* struct hdac_ext2_link - HDAudio extended+alternate link
*
@@ -33,6 +36,7 @@
* @leptr: extended link pointer
* @eml_lock: mutual exclusion to access shared registers e.g. CPA/SPA bits
* in LCTL register
+ * @sublink_ref_count: array of refcounts, required to power-manage sublinks independently
* @base_ptr: pointer to shim/ip/shim_vs space
* @instance_offset: offset between each of @slcount instances managed by link
* @shim_offset: offset to SHIM register base
@@ -53,6 +57,7 @@ struct hdac_ext2_link {
u32 leptr;
struct mutex eml_lock; /* prevent concurrent access to e.g. CPA/SPA */
+ int sublink_ref_count[HDAML_MAX_SUBLINKS];
/* internal values computed from LCAP contents */
void __iomem *base_ptr;
@@ -641,8 +646,13 @@ static int hdac_bus_eml_power_up_base(struct hdac_bus *bus, bool alt, int elid,
if (eml_lock)
mutex_lock(&h2link->eml_lock);
- if (++hlink->ref_count > 1)
- goto skip_init;
+ if (!alt) {
+ if (++hlink->ref_count > 1)
+ goto skip_init;
+ } else {
+ if (++h2link->sublink_ref_count[sublink] > 1)
+ goto skip_init;
+ }
ret = hdaml_link_init(hlink->ml_addr + AZX_REG_ML_LCTL, sublink);
@@ -684,9 +694,13 @@ static int hdac_bus_eml_power_down_base(struct hdac_bus *bus, bool alt, int elid
if (eml_lock)
mutex_lock(&h2link->eml_lock);
- if (--hlink->ref_count > 0)
- goto skip_shutdown;
-
+ if (!alt) {
+ if (--hlink->ref_count > 0)
+ goto skip_shutdown;
+ } else {
+ if (--h2link->sublink_ref_count[sublink] > 0)
+ goto skip_shutdown;
+ }
ret = hdaml_link_shutdown(hlink->ml_addr + AZX_REG_ML_LCTL, sublink);
skip_shutdown: