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