ASoC: dsp: Synchronise adm and rtac commands

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.

Change-Id: Id89d98217dc5cad3703e5d545ddee21cb145c874
Signed-off-by: Soumya Managoli <smanag@codeaurora.org>
diff --git a/dsp/q6adm.c b/dsp/q6adm.c
index 51ca185..708cc0f 100644
--- a/dsp/q6adm.c
+++ b/dsp/q6adm.c
@@ -95,6 +95,7 @@
 	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 @@
 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 @@
 	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 @@
 		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 @@
 					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 @@
 			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 @@
 				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 @@
 	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 @@
 
 void adm_exit(void)
 {
+	mutex_destroy(&this_adm.adm_apr_lock);
 	if (this_adm.apr)
 		adm_reset_data();
 	adm_delete_cal_data();