[PATCH 2/2] ASoC: qcom: qdsp6: q6adm: Add reference count for opening/closing copps
From: Stephan Gerhold
Date: Thu Apr 03 2025 - 13:38:49 EST
---
sound/soc/qcom/qdsp6/q6adm.c | 71 ++++++++++++++++++++++--------------
1 file changed, 43 insertions(+), 28 deletions(-)
diff --git a/sound/soc/qcom/qdsp6/q6adm.c b/sound/soc/qcom/qdsp6/q6adm.c
index b4879cac76a6..b073980bb967 100644
--- a/sound/soc/qcom/qdsp6/q6adm.c
+++ b/sound/soc/qcom/qdsp6/q6adm.c
@@ -51,6 +51,9 @@ struct q6copp {
wait_queue_head_t wait;
struct list_head node;
struct q6adm *adm;
+
+ int open_count;
+ struct mutex open_lock;
};
struct q6adm {
@@ -396,35 +399,43 @@ struct q6copp *q6adm_open(struct device *dev, int port_id, int path, int rate,
copp = q6adm_find_matching_copp(adm, port_id, topology, perf_mode,
rate, channel_mode, bit_width, app_type);
- if (copp) {
- dev_err(dev, "Found Matching Copp 0x%x\n", copp->copp_idx);
- return copp;
- }
+ if (!copp) {
+ spin_lock_irqsave(&adm->copps_list_lock, flags);
+ copp = q6adm_alloc_copp(adm, port_id);
+ if (IS_ERR(copp)) {
+ spin_unlock_irqrestore(&adm->copps_list_lock, flags);
+ return ERR_CAST(copp);
+ }
- spin_lock_irqsave(&adm->copps_list_lock, flags);
- copp = q6adm_alloc_copp(adm, port_id);
- if (IS_ERR(copp)) {
+ kref_init(&copp->refcount);
+ copp->topology = topology;
+ copp->mode = perf_mode;
+ copp->rate = rate;
+ copp->channels = channel_mode;
+ copp->bit_width = bit_width;
+ copp->app_type = app_type;
+ mutex_init(&copp->open_lock);
+
+ list_add_tail(&copp->node, &adm->copps_list);
spin_unlock_irqrestore(&adm->copps_list_lock, flags);
- return ERR_CAST(copp);
+ } else {
+ dev_dbg(dev, "Found Matching Copp 0x%x\n", copp->copp_idx);
}
- kref_init(&copp->refcount);
- copp->topology = topology;
- copp->mode = perf_mode;
- copp->rate = rate;
- copp->channels = channel_mode;
- copp->bit_width = bit_width;
- copp->app_type = app_type;
-
- list_add_tail(&copp->node, &adm->copps_list);
- spin_unlock_irqrestore(&adm->copps_list_lock, flags);
-
- ret = q6adm_device_open(adm, copp, port_id, path, topology,
- channel_mode, bit_width, rate);
- if (ret < 0) {
- kref_put(&copp->refcount, q6adm_free_copp);
- return ERR_PTR(ret);
+ mutex_lock(&copp->open_lock);
+ if (copp->open_count == 0) {
+ ret = q6adm_device_open(adm, copp, port_id, path, topology,
+ channel_mode, bit_width, rate);
+ if (ret < 0) {
+ mutex_unlock(&copp->open_lock);
+ kref_put(&copp->refcount, q6adm_free_copp);
+ return ERR_PTR(ret);
+ }
+ copp->open_count = 1;
+ } else {
+ copp->open_count++;
}
+ mutex_unlock(&copp->open_lock);
return copp;
}
@@ -570,11 +581,15 @@ int q6adm_close(struct device *dev, struct q6copp *copp)
struct q6adm *adm = dev_get_drvdata(dev->parent);
int ret = 0;
- ret = q6adm_device_close(adm, copp, copp->afe_port, copp->copp_idx);
- if (ret < 0) {
- dev_err(adm->dev, "Failed to close copp %d\n", ret);
- return ret;
+ mutex_lock(&copp->open_lock);
+ if (--copp->open_count == 0) {
+ ret = q6adm_device_close(adm, copp, copp->afe_port, copp->copp_idx);
+ if (ret < 0) {
+ dev_err(adm->dev, "Failed to close copp %d\n", ret);
+ return ret;
+ }
}
+ mutex_unlock(&copp->open_lock);
kref_put(&copp->refcount, q6adm_free_copp);
--
2.47.2