summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSoumya Managoli <smanag@codeaurora.org>2020-04-28 09:16:55 +0530
committerYung Ti Su <andysu@google.com>2021-03-22 08:54:28 +0000
commita752ee8f89b828aba3cd561d44e440c673909df6 (patch)
tree0760836af0e1f43f6547e580b5518ae85f2d87d3
parent3a2268cfd593523f915ddf39183d07e14bad290a (diff)
downloadmsm-extra-a752ee8f89b828aba3cd561d44e440c673909df6.tar.gz
Race condition observed while processing the set_pp_params command responses sent back to back by adsp for commands sent from adm and rtac. Handle this by synchronising the get/set pp_params command in both the drivers. QCT CR-2771103 Bug: 181819518 Change-Id: Id89d98217dc5cad3703e5d545ddee21cb145c874 Signed-off-by: Soumya Managoli <smanag@codeaurora.org>
-rw-r--r--dsp/q6adm.c107
-rw-r--r--dsp/rtac.c30
-rw-r--r--include/dsp/q6adm-v2.h2
3 files changed, 81 insertions, 58 deletions
diff --git a/dsp/q6adm.c b/dsp/q6adm.c
index 51ca185b..708cc0fd 100644
--- a/dsp/q6adm.c
+++ b/dsp/q6adm.c
@@ -95,6 +95,7 @@ struct adm_ctl {
struct param_outband outband_memmap;
struct source_tracking_data sourceTrackingData;
+ struct mutex adm_apr_lock;
int set_custom_topology;
int ec_ref_rx;
int num_ec_ref_rx_chans;
@@ -870,6 +871,58 @@ exit:
EXPORT_SYMBOL(adm_set_custom_chmix_cfg);
/*
+ * adm_apr_send_pkt : returns 0 on success, negative otherwise.
+ */
+int adm_apr_send_pkt(void *data, wait_queue_head_t *wait,
+ int port_idx, int copp_idx)
+{
+ int ret = 0;
+ atomic_t *copp_stat = NULL;
+ wait = &this_adm.copp.wait[port_idx][copp_idx];
+
+ if (!wait)
+ return -EINVAL;
+
+ mutex_lock(&this_adm.adm_apr_lock);
+ pr_debug("%s: port idx %d copp idx %d\n", __func__,
+ port_idx, copp_idx);
+ copp_stat = &this_adm.copp.stat[port_idx][copp_idx];
+ atomic_set(copp_stat, -1);
+
+ if (atomic_read(&this_adm.copp.cnt[port_idx][copp_idx]) == 0) {
+ pr_err("%s: port[0x%x] coppid[0x%x] is not active, ERROR\n",
+ __func__, port_idx, copp_idx);
+ mutex_unlock(&this_adm.adm_apr_lock);
+ return -EINVAL;
+ }
+
+ ret = apr_send_pkt(this_adm.apr, data);
+ if (ret > 0) {
+ ret = wait_event_timeout(*wait,
+ atomic_read(copp_stat) >= 0,
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (atomic_read(copp_stat) > 0) {
+ pr_err("%s: DSP returned error[%s]\n", __func__,
+ adsp_err_get_err_str(atomic_read(copp_stat)));
+ ret = adsp_err_get_lnx_err_code(atomic_read(copp_stat));
+ } else if (!ret) {
+ pr_err_ratelimited("%s: request timedout\n",
+ __func__);
+ ret = -ETIMEDOUT;
+ } else {
+ ret = 0;
+ }
+ } else if (ret == 0) {
+ pr_err("%s: packet not transmitted\n", __func__);
+ /* apr_send_pkt can return 0 when nothing is transmitted */
+ ret = -EINVAL;
+ }
+
+ mutex_unlock(&this_adm.adm_apr_lock);
+ return ret;
+}
+
+/*
* With pre-packed data, only the opcode differes from V5 and V6.
* Use q6common_pack_pp_params to pack the data correctly.
*/
@@ -880,7 +933,6 @@ int adm_set_pp_params(int port_id, int copp_idx,
struct adm_cmd_set_pp_params *adm_set_params = NULL;
int size = 0;
int port_idx = 0;
- atomic_t *copp_stat = NULL;
int ret = 0;
port_id = afe_convert_virtual_to_portid(port_id);
@@ -938,32 +990,9 @@ int adm_set_pp_params(int port_id, int copp_idx,
ret = -EINVAL;
goto done;
}
-
- copp_stat = &this_adm.copp.stat[port_idx][copp_idx];
- atomic_set(copp_stat, -1);
- ret = apr_send_pkt(this_adm.apr, (uint32_t *) adm_set_params);
- if (ret < 0) {
- pr_err("%s: Set params APR send failed port = 0x%x ret %d\n",
- __func__, port_id, ret);
- goto done;
- }
- ret = wait_event_timeout(this_adm.copp.wait[port_idx][copp_idx],
- atomic_read(copp_stat) >= 0,
- msecs_to_jiffies(TIMEOUT_MS));
- if (!ret) {
- pr_err("%s: Set params timed out port = 0x%x\n", __func__,
- port_id);
- ret = -ETIMEDOUT;
- goto done;
- }
- if (atomic_read(copp_stat) > 0) {
- pr_err("%s: DSP returned error[%s]\n", __func__,
- adsp_err_get_err_str(atomic_read(copp_stat)));
- ret = adsp_err_get_lnx_err_code(atomic_read(copp_stat));
- goto done;
- }
-
- ret = 0;
+ ret = adm_apr_send_pkt((uint32_t *) adm_set_params,
+ &this_adm.copp.wait[port_idx][copp_idx],
+ port_idx, copp_idx);
done:
kfree(adm_set_params);
return ret;
@@ -1601,8 +1630,15 @@ static int32_t adm_callback(struct apr_client_data *data, void *priv)
this_adm.sourceTrackingData.
apr_cmd_status = payload[1];
else if (rtac_make_adm_callback(payload,
- data->payload_size))
- break;
+ data->payload_size)) {
+ pr_debug("%s: rtac cmd response\n",
+ __func__);
+ }
+ atomic_set(&this_adm.copp.stat[port_idx]
+ [copp_idx], payload[1]);
+ wake_up(
+ &this_adm.copp.wait[port_idx][copp_idx]);
+ break;
/*
* if soft volume is called and already
* interrupted break out of the sequence here
@@ -1611,8 +1647,8 @@ static int32_t adm_callback(struct apr_client_data *data, void *priv)
case ADM_CMD_DEVICE_CLOSE_V5:
case ADM_CMD_DEVICE_OPEN_V6:
case ADM_CMD_DEVICE_OPEN_V8:
- pr_debug("%s: Basic callback received, wake up.\n",
- __func__);
+ pr_debug("%s: Basic callback received for 0x%x, wake up.\n",
+ __func__, payload[0]);
atomic_set(&this_adm.copp.stat[port_idx]
[copp_idx], payload[1]);
wake_up(
@@ -1745,8 +1781,13 @@ static int32_t adm_callback(struct apr_client_data *data, void *priv)
this_adm.sourceTrackingData.apr_cmd_status =
payload[0];
else if (rtac_make_adm_callback(payload,
- data->payload_size))
+ data->payload_size)) {
+ pr_debug("%s: rtac cmd response\n", __func__);
+ atomic_set(&this_adm.copp.stat[port_idx][copp_idx],
+ payload[0]);
+ wake_up(&this_adm.copp.wait[port_idx][copp_idx]);
break;
+ }
idx = ADM_GET_PARAMETER_LENGTH * copp_idx;
if (payload[0] == 0 && data->payload_size > 0) {
@@ -5504,6 +5545,7 @@ int __init adm_init(void)
this_adm.ffecns_port_id = -1;
init_waitqueue_head(&this_adm.matrix_map_wait);
init_waitqueue_head(&this_adm.adm_wait);
+ mutex_init(&this_adm.adm_apr_lock);
for (i = 0; i < AFE_MAX_PORTS; i++) {
for (j = 0; j < MAX_COPPS_PER_PORT; j++) {
@@ -5528,6 +5570,7 @@ int __init adm_init(void)
void adm_exit(void)
{
+ mutex_destroy(&this_adm.adm_apr_lock);
if (this_adm.apr)
adm_reset_data();
adm_delete_cal_data();
diff --git a/dsp/rtac.c b/dsp/rtac.c
index c77b5f09..ed298e9c 100644
--- a/dsp/rtac.c
+++ b/dsp/rtac.c
@@ -728,7 +728,6 @@ bool rtac_make_adm_callback(uint32_t *payload, u32 payload_size)
atomic_set(&rtac_common.apr_err_code, payload[1]);
atomic_set(&rtac_adm_apr_data.cmd_state, 0);
- wake_up(&rtac_adm_apr_data.cmd_wait);
return true;
}
@@ -880,33 +879,12 @@ int send_adm_apr(void *buf, u32 opcode)
pr_debug("%s: Sending RTAC command ioctl 0x%x, paddr 0x%pK\n",
__func__, opcode,
&rtac_cal[ADM_RTAC_CAL].cal_data.paddr);
+ mutex_unlock(&rtac_adm_apr_mutex);
- result = apr_send_pkt(rtac_adm_apr_data.apr_handle,
- (uint32_t *)rtac_adm_buffer);
- if (result < 0) {
- pr_err("%s: Set params failed copp = %d\n", __func__, copp_id);
- goto err;
- }
- /* Wait for the callback */
- result = wait_event_timeout(rtac_adm_apr_data.cmd_wait,
- (atomic_read(&rtac_adm_apr_data.cmd_state) == 0),
- msecs_to_jiffies(TIMEOUT_MS));
- if (!result) {
- pr_err("%s: Set params timed out copp = %d\n", __func__,
- copp_id);
- goto err;
- }
- if (atomic_read(&rtac_common.apr_err_code)) {
- pr_err("%s: DSP returned error code = [%s], opcode = 0x%x\n",
- __func__, adsp_err_get_err_str(atomic_read(
- &rtac_common.apr_err_code)),
- opcode);
- result = adsp_err_get_lnx_err_code(
- atomic_read(
- &rtac_common.apr_err_code));
- goto err;
- }
+ result = adm_apr_send_pkt((uint32_t *)rtac_adm_buffer,
+ NULL, port_idx, copp_idx);
+ mutex_lock(&rtac_adm_apr_mutex);
if (opcode == ADM_CMD_GET_PP_PARAMS_V5) {
bytes_returned = ((u32 *)rtac_cal[ADM_RTAC_CAL].cal_data.
kvaddr)[2] + 3 * sizeof(u32);
diff --git a/include/dsp/q6adm-v2.h b/include/dsp/q6adm-v2.h
index 644855d0..20b2450b 100644
--- a/include/dsp/q6adm-v2.h
+++ b/include/dsp/q6adm-v2.h
@@ -229,4 +229,6 @@ void msm_dts_srs_acquire_lock(void);
void msm_dts_srs_release_lock(void);
void adm_set_native_mode(int mode);
int adm_set_ffecns_freeze_event(bool ffecns_freeze_event);
+int adm_apr_send_pkt(void *data, wait_queue_head_t *wait,
+ int port_idx, int copp_idx);
#endif /* __Q6_ADM_V2_H__ */