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
This commit is contained in:
Pierre-Louis Bossart 2023-05-12 12:46:06 -05:00 committed by Mark Brown
parent f63550e2b1
commit 7430dea494
No known key found for this signature in database
GPG Key ID: 24D68B725D5487D0
1 changed files with 19 additions and 5 deletions

View File

@ -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: