drivers: dai: alh: fix refcount logic for ALH ownership

Refcounting is used to track ALH block usage and to
call alh_claim_ownership()/alh_release_ownership() accordingly.
This is however incorrectly done on ALH instance basis, which
means when one instance is released, ownership can be released
even though one ALH instance is still active.

Fix the logic by tracking ALH usage as a global property
which matches the alh_claim_ownership/alh_release_ownership
semantics.

Link: https://github.com/thesofproject/sof/issues/7759
Signed-off-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
This commit is contained in:
Kai Vehmanen 2023-08-17 21:48:15 +03:00 committed by Carles Cufí
commit f764e7e737
2 changed files with 16 additions and 11 deletions

View file

@ -22,6 +22,9 @@ LOG_MODULE_REGISTER(LOG_DOMAIN);
#include "alh.h"
/* global data shared between all alh instances */
struct dai_alh_global_shared dai_alh_global;
/* Digital Audio interface formatting */
static int dai_alh_set_config_tplg(struct dai_intel_alh *dp, const void *spec_config)
{
@ -157,38 +160,36 @@ static const struct dai_properties *dai_alh_get_properties(const struct device *
static int dai_alh_probe(const struct device *dev)
{
struct dai_intel_alh *dp = (struct dai_intel_alh *)dev->data;
k_spinlock_key_t key;
LOG_DBG("%s", __func__);
key = k_spin_lock(&dp->lock);
key = k_spin_lock(&dai_alh_global.lock);
if (dp->sref == 0) {
if (dai_alh_global.sref == 0) {
alh_claim_ownership();
}
dp->sref++;
dai_alh_global.sref++;
k_spin_unlock(&dp->lock, key);
k_spin_unlock(&dai_alh_global.lock, key);
return 0;
}
static int dai_alh_remove(const struct device *dev)
{
struct dai_intel_alh *dp = (struct dai_intel_alh *)dev->data;
k_spinlock_key_t key;
LOG_DBG("%s", __func__);
key = k_spin_lock(&dp->lock);
key = k_spin_lock(&dai_alh_global.lock);
if (--dp->sref == 0) {
if (--dai_alh_global.sref == 0) {
alh_release_ownership();
}
k_spin_unlock(&dp->lock, key);
k_spin_unlock(&dai_alh_global.lock, key);
return 0;
}

View file

@ -107,10 +107,14 @@ struct dai_intel_alh_pdata {
struct dai_intel_alh {
uint32_t index; /**< index */
struct k_spinlock lock; /**< locking mechanism */
int sref; /**< simple ref counter, guarded by lock */
struct dai_intel_alh_plat_data plat_data;
struct dai_intel_alh_pdata priv_data;
};
/* Common data for all ALH DAI instances */
struct dai_alh_global_shared {
struct k_spinlock lock; /**< locking mechanism */
int sref; /**< simple ref counter, guarded by lock */
};
#endif