Unverified Commit 7430dea4 authored by Pierre-Louis Bossart's avatar Pierre-Louis Bossart Committed by Mark Brown
Browse files

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: default avatarPierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Reviewed-by: default avatarRanjani Sridharan <ranjani.sridharan@linux.intel.com>
Reviewed-by: default avatarBard 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: default avatarMark Brown <broonie@kernel.org>
parent f63550e2
Loading
Loading
Loading
Loading
+19 −5
Original line number Diff line number Diff line
@@ -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 (!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 (!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: