mirror of
https://github.com/torvalds/linux.git
synced 2025-12-07 20:06:24 +00:00
ASoC: qcom: q6adm: the the copp device only during last instance
A matching Common object post processing instance is normally resused
across multiple streams. However currently we close this on DSP
even though there is a refcount on this copp object, this can result in
below error.
q6routing ab00000.remoteproc:glink-edge:apr:service@8:routing: Found Matching Copp 0x0
qcom-q6adm aprsvc:service:4:8: cmd = 0x10325 return error = 0x2
q6routing ab00000.remoteproc:glink-edge:apr:service@8:routing: DSP returned error[2]
q6routing ab00000.remoteproc:glink-edge:apr:service@8:routing: Found Matching Copp 0x0
qcom-q6adm aprsvc:service:4:8: cmd = 0x10325 return error = 0x2
q6routing ab00000.remoteproc:glink-edge:apr:service@8:routing: DSP returned error[2]
qcom-q6adm aprsvc:service:4:8: cmd = 0x10327 return error = 0x2
qcom-q6adm aprsvc:service:4:8: DSP returned error[2]
qcom-q6adm aprsvc:service:4:8: Failed to close copp -22
qcom-q6adm aprsvc:service:4:8: cmd = 0x10327 return error = 0x2
qcom-q6adm aprsvc:service:4:8: DSP returned error[2]
qcom-q6adm aprsvc:service:4:8: Failed to close copp -22
Fix this by addressing moving the adm_close to copp_kref destructor
callback.
Fixes: 7b20b2be51 ("ASoC: qdsp6: q6adm: Add q6adm driver")
Cc: Stable@vger.kernel.org
Reported-by: Martino Facchin <m.facchin@arduino.cc>
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@oss.qualcomm.com>
Tested-by: Alexey Klimov <alexey.klimov@linaro.org> # RB5, RB3
Link: https://patch.msgid.link/20251023102444.88158-3-srinivas.kandagatla@oss.qualcomm.com
Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
committed by
Mark Brown
parent
950a4e5788
commit
74cc4f3ea4
@@ -109,11 +109,75 @@ static struct q6copp *q6adm_find_copp(struct q6adm *adm, int port_idx,
|
||||
|
||||
}
|
||||
|
||||
static int q6adm_apr_send_copp_pkt(struct q6adm *adm, struct q6copp *copp,
|
||||
struct apr_pkt *pkt, uint32_t rsp_opcode)
|
||||
{
|
||||
struct device *dev = adm->dev;
|
||||
uint32_t opcode = pkt->hdr.opcode;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&adm->lock);
|
||||
copp->result.opcode = 0;
|
||||
copp->result.status = 0;
|
||||
ret = apr_send_pkt(adm->apr, pkt);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Failed to send APR packet\n");
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Wait for the callback with copp id */
|
||||
if (rsp_opcode)
|
||||
ret = wait_event_timeout(copp->wait,
|
||||
(copp->result.opcode == opcode) ||
|
||||
(copp->result.opcode == rsp_opcode),
|
||||
msecs_to_jiffies(TIMEOUT_MS));
|
||||
else
|
||||
ret = wait_event_timeout(copp->wait,
|
||||
(copp->result.opcode == opcode),
|
||||
msecs_to_jiffies(TIMEOUT_MS));
|
||||
|
||||
if (!ret) {
|
||||
dev_err(dev, "ADM copp cmd timedout\n");
|
||||
ret = -ETIMEDOUT;
|
||||
} else if (copp->result.status > 0) {
|
||||
dev_err(dev, "DSP returned error[%d]\n",
|
||||
copp->result.status);
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
err:
|
||||
mutex_unlock(&adm->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int q6adm_device_close(struct q6adm *adm, struct q6copp *copp,
|
||||
int port_id, int copp_idx)
|
||||
{
|
||||
struct apr_pkt close;
|
||||
|
||||
close.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
|
||||
APR_HDR_LEN(APR_HDR_SIZE),
|
||||
APR_PKT_VER);
|
||||
close.hdr.pkt_size = sizeof(close);
|
||||
close.hdr.src_port = port_id;
|
||||
close.hdr.dest_port = copp->id;
|
||||
close.hdr.token = port_id << 16 | copp_idx;
|
||||
close.hdr.opcode = ADM_CMD_DEVICE_CLOSE_V5;
|
||||
|
||||
return q6adm_apr_send_copp_pkt(adm, copp, &close, 0);
|
||||
}
|
||||
|
||||
static void q6adm_free_copp(struct kref *ref)
|
||||
{
|
||||
struct q6copp *c = container_of(ref, struct q6copp, refcount);
|
||||
struct q6adm *adm = c->adm;
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
ret = q6adm_device_close(adm, c, c->afe_port, c->copp_idx);
|
||||
if (ret < 0)
|
||||
dev_err(adm->dev, "Failed to close copp %d\n", ret);
|
||||
|
||||
spin_lock_irqsave(&adm->copps_list_lock, flags);
|
||||
clear_bit(c->copp_idx, &adm->copp_bitmap[c->afe_port]);
|
||||
@@ -155,13 +219,13 @@ static int q6adm_callback(struct apr_device *adev, struct apr_resp_pkt *data)
|
||||
switch (result->opcode) {
|
||||
case ADM_CMD_DEVICE_OPEN_V5:
|
||||
case ADM_CMD_DEVICE_CLOSE_V5:
|
||||
copp = q6adm_find_copp(adm, port_idx, copp_idx);
|
||||
if (!copp)
|
||||
return 0;
|
||||
|
||||
copp->result = *result;
|
||||
wake_up(&copp->wait);
|
||||
kref_put(&copp->refcount, q6adm_free_copp);
|
||||
list_for_each_entry(copp, &adm->copps_list, node) {
|
||||
if ((port_idx == copp->afe_port) && (copp_idx == copp->copp_idx)) {
|
||||
copp->result = *result;
|
||||
wake_up(&copp->wait);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ADM_CMD_MATRIX_MAP_ROUTINGS_V5:
|
||||
adm->result = *result;
|
||||
@@ -234,65 +298,6 @@ static struct q6copp *q6adm_alloc_copp(struct q6adm *adm, int port_idx)
|
||||
return c;
|
||||
}
|
||||
|
||||
static int q6adm_apr_send_copp_pkt(struct q6adm *adm, struct q6copp *copp,
|
||||
struct apr_pkt *pkt, uint32_t rsp_opcode)
|
||||
{
|
||||
struct device *dev = adm->dev;
|
||||
uint32_t opcode = pkt->hdr.opcode;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&adm->lock);
|
||||
copp->result.opcode = 0;
|
||||
copp->result.status = 0;
|
||||
ret = apr_send_pkt(adm->apr, pkt);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Failed to send APR packet\n");
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Wait for the callback with copp id */
|
||||
if (rsp_opcode)
|
||||
ret = wait_event_timeout(copp->wait,
|
||||
(copp->result.opcode == opcode) ||
|
||||
(copp->result.opcode == rsp_opcode),
|
||||
msecs_to_jiffies(TIMEOUT_MS));
|
||||
else
|
||||
ret = wait_event_timeout(copp->wait,
|
||||
(copp->result.opcode == opcode),
|
||||
msecs_to_jiffies(TIMEOUT_MS));
|
||||
|
||||
if (!ret) {
|
||||
dev_err(dev, "ADM copp cmd timedout\n");
|
||||
ret = -ETIMEDOUT;
|
||||
} else if (copp->result.status > 0) {
|
||||
dev_err(dev, "DSP returned error[%d]\n",
|
||||
copp->result.status);
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
err:
|
||||
mutex_unlock(&adm->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int q6adm_device_close(struct q6adm *adm, struct q6copp *copp,
|
||||
int port_id, int copp_idx)
|
||||
{
|
||||
struct apr_pkt close;
|
||||
|
||||
close.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
|
||||
APR_HDR_LEN(APR_HDR_SIZE),
|
||||
APR_PKT_VER);
|
||||
close.hdr.pkt_size = sizeof(close);
|
||||
close.hdr.src_port = port_id;
|
||||
close.hdr.dest_port = copp->id;
|
||||
close.hdr.token = port_id << 16 | copp_idx;
|
||||
close.hdr.opcode = ADM_CMD_DEVICE_CLOSE_V5;
|
||||
|
||||
return q6adm_apr_send_copp_pkt(adm, copp, &close, 0);
|
||||
}
|
||||
|
||||
static struct q6copp *q6adm_find_matching_copp(struct q6adm *adm,
|
||||
int port_id, int topology,
|
||||
int mode, int rate,
|
||||
@@ -567,15 +572,6 @@ EXPORT_SYMBOL_GPL(q6adm_matrix_map);
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
kref_put(&copp->refcount, q6adm_free_copp);
|
||||
|
||||
return 0;
|
||||
|
||||
Reference in New Issue
Block a user