ASoC: msm: qdsp6v2: Fix bugs in listen client and server

Correct LSM idx in APR sevices table. Free memory allocated for
snd_model when not needed. Unlock mutex before locking same mutex
again in the same thread.

CRs-Fixed: 487983
Change-Id: I392321cddfd53746f63955993801f523e17330f5
Signed-off-by: Kiran Kandi <kkandi@codeaurora.org>
diff --git a/arch/arm/mach-msm/qdsp6v2/apr.c b/arch/arm/mach-msm/qdsp6v2/apr.c
index 6e60db1..8d9ad29 100644
--- a/arch/arm/mach-msm/qdsp6v2/apr.c
+++ b/arch/arm/mach-msm/qdsp6v2/apr.c
@@ -118,7 +118,7 @@
 	},
 	{
 		.name = "LSM",
-		.idx = 9,
+		.idx = 10,
 		.id = APR_SVC_LSM,
 		.client_id = APR_CLIENT_AUDIO,
 	},
diff --git a/include/sound/q6afe-v2.h b/include/sound/q6afe-v2.h
index 1389b2a..2e4c7c1 100644
--- a/include/sound/q6afe-v2.h
+++ b/include/sound/q6afe-v2.h
@@ -197,6 +197,8 @@
 enum afe_mad_type afe_port_get_mad_type(u16 port_id);
 int afe_set_config(enum afe_config_type config_type, void *config_data,
 		   int arg);
+void afe_clear_config(enum afe_config_type config);
+bool afe_has_config(enum afe_config_type config);
 
 void afe_set_aanc_info(struct aanc_data *aanc_info);
 #endif /* __Q6AFE_V2_H__ */
diff --git a/include/sound/q6lsm.h b/include/sound/q6lsm.h
index e9ca91d..d7a01a0 100644
--- a/include/sound/q6lsm.h
+++ b/include/sound/q6lsm.h
@@ -124,6 +124,7 @@
 int q6lsm_start(struct lsm_client *client, bool wait);
 int q6lsm_stop(struct lsm_client *client, bool wait);
 int q6lsm_snd_model_buf_alloc(struct lsm_client *client, uint32_t len);
+int q6lsm_snd_model_buf_free(struct lsm_client *client);
 int q6lsm_close(struct lsm_client *client);
 int q6lsm_register_sound_model(struct lsm_client *client,
 			       enum lsm_detection_mode mode, u16 minkeyword,
diff --git a/sound/soc/msm/qdsp6v2/msm-lsm-client.c b/sound/soc/msm/qdsp6v2/msm-lsm-client.c
index 363fb15..f76d455 100644
--- a/sound/soc/msm/qdsp6v2/msm-lsm-client.c
+++ b/sound/soc/msm/qdsp6v2/msm-lsm-client.c
@@ -117,8 +117,8 @@
 
 		if (copy_from_user(prtd->lsm_client->sound_model.data,
 				   snd_model.data, snd_model.data_size)) {
-			pr_err("%s: copy from user data failed size %d\n",
-			       __func__, snd_model.data_size);
+			pr_err("%s: copy from user data failed data %p size %d\n",
+			       __func__, snd_model.data, snd_model.data_size);
 			rc = -EFAULT;
 			break;
 		}
@@ -128,9 +128,12 @@
 						snd_model.min_keyw_confidence,
 						snd_model.min_user_confidence,
 						snd_model.detect_failure);
-		if (rc < 0)
+		if (rc < 0) {
 			pr_err("%s: q6lsm_register_sound_model failed =%d\n",
 			       __func__, rc);
+			q6lsm_snd_model_buf_free(prtd->lsm_client);
+		}
+
 		break;
 
 	case SNDRV_LSM_DEREG_SND_MODEL:
@@ -213,11 +216,10 @@
 		pr_debug("%s: Stopping LSM client session\n", __func__);
 		if (prtd->lsm_client->started) {
 			ret = q6lsm_stop(prtd->lsm_client, true);
-			if (!ret) {
-				prtd->lsm_client->started = false;
-				pr_debug("%s: LSM client session stopped\n",
-					 __func__);
-			}
+			if (!ret)
+				pr_debug("%s: LSM client session stopped %d\n",
+					 __func__, ret);
+			prtd->lsm_client->started = false;
 		}
 		break;
 
@@ -258,10 +260,10 @@
 	}
 	ret = q6lsm_open(prtd->lsm_client);
 	if (ret < 0) {
-		pr_err("%s: lsm out open failed\n", __func__);
+		pr_err("%s: lsm open failed, %d\n", __func__, ret);
 		q6lsm_client_free(prtd->lsm_client);
 		kfree(prtd);
-		return -ENOMEM;
+		return ret;
 	}
 
 	pr_debug("%s: Session ID %d\n", __func__, prtd->lsm_client->session);
diff --git a/sound/soc/msm/qdsp6v2/q6afe.c b/sound/soc/msm/qdsp6v2/q6afe.c
index 7de058d..3bb31f9 100644
--- a/sound/soc/msm/qdsp6v2/q6afe.c
+++ b/sound/soc/msm/qdsp6v2/q6afe.c
@@ -50,6 +50,7 @@
 };
 
 static atomic_t afe_ports_mad_type[SLIMBUS_PORT_LAST - SLIMBUS_0_RX];
+static unsigned long afe_configured_cmd;
 
 static struct afe_ctl this_afe;
 
@@ -1053,10 +1054,28 @@
 		ret = -EINVAL;
 	}
 
+	if (!ret)
+		set_bit(config_type, &afe_configured_cmd);
+
 	pr_debug("%s: leave ret %d\n", __func__, ret);
 	return ret;
 }
 
+/*
+ * afe_clear_config - If SSR happens ADSP loses AFE configs, let AFE driver know
+ *		      about the state so client driver can wait until AFE is
+ *		      reconfigured.
+ */
+void afe_clear_config(enum afe_config_type config)
+{
+	clear_bit(config, &afe_configured_cmd);
+}
+
+bool afe_has_config(enum afe_config_type config)
+{
+	return !!test_bit(config, &afe_configured_cmd);
+}
+
 static int afe_send_cmd_port_start(u16 port_id)
 {
 	struct afe_port_cmd_device_start start;
diff --git a/sound/soc/msm/qdsp6v2/q6lsm.c b/sound/soc/msm/qdsp6v2/q6lsm.c
index daa2916..c5483ee 100644
--- a/sound/soc/msm/qdsp6v2/q6lsm.c
+++ b/sound/soc/msm/qdsp6v2/q6lsm.c
@@ -31,6 +31,7 @@
 #include <mach/memory.h>
 #include <mach/debug_mm.h>
 #include "audio_acdb.h"
+#include "q6core.h"
 
 #define APR_TIMEOUT	(5 * HZ)
 #define LSM_CAL_SIZE	4096
@@ -70,7 +71,6 @@
 
 static int q6lsm_mmapcallback(struct apr_client_data *data, void *priv);
 static int q6lsm_send_cal(struct lsm_client *client);
-static int q6lsm_snd_model_buf_free(struct lsm_client *client);
 
 static int q6lsm_callback(struct apr_client_data *data, void *priv)
 {
@@ -318,6 +318,13 @@
 	int rc;
 	struct lsm_stream_cmd_open_tx open;
 
+	if (!afe_has_config(AFE_CDC_REGISTERS_CONFIG) ||
+	    !afe_has_config(AFE_SLIMBUS_SLAVE_CONFIG)) {
+		pr_err("%s: AFE isn't configured yet\n", __func__);
+		rc = -EAGAIN;
+		goto exit;
+	}
+
 	memset(&open, 0, sizeof(open));
 	q6lsm_add_hdr(client, &open.hdr, sizeof(open), true);
 
@@ -330,6 +337,7 @@
 		pr_err("%s: Open failed opcode 0x%x, rc %d\n",
 		       __func__, open.hdr.opcode, rc);
 
+exit:
 	pr_debug("%s: leave %d\n", __func__, rc);
 	return rc;
 }
@@ -468,9 +476,10 @@
 		       cmd.hdr.opcode, rc);
 	} else {
 		pr_debug("%s: Deregister sound model succeeded\n", __func__);
-		q6lsm_snd_model_buf_free(client);
 	}
 
+	q6lsm_snd_model_buf_free(client);
+
 	return rc;
 }
 
@@ -500,8 +509,8 @@
 	int rc;
 	int cmd_size = 0;
 
-	pr_debug("%s: dma_addr_p 0x%x, dma_buf_sz %d, session %d\n",
-		 __func__, dma_addr_p, dma_buf_sz, client->session);
+	pr_debug("%s: dma_addr_p 0x%x, dma_buf_sz %d, mmap_p 0x%p, session %d\n",
+		 __func__, dma_addr_p, dma_buf_sz, mmap_p, client->session);
 
 	cmd_size = sizeof(struct avs_cmd_shared_mem_map_regions) +
 		   sizeof(struct avs_shared_map_region_payload);
@@ -537,6 +546,29 @@
 	return rc;
 }
 
+static int q6lsm_memory_unmap_regions(struct lsm_client *client,
+				      uint32_t handle)
+{
+	struct avs_cmd_shared_mem_unmap_regions unmap;
+	int rc = 0;
+	int cmd_size = 0;
+
+	cmd_size = sizeof(struct avs_cmd_shared_mem_unmap_regions);
+	q6lsm_add_mmaphdr(client, &unmap.hdr, cmd_size,
+			  true, (client->session << 8));
+	unmap.hdr.opcode = LSM_SESSION_CMD_SHARED_MEM_UNMAP_REGIONS;
+	unmap.mem_map_handle = handle;
+
+	pr_debug("%s: unmap handle 0x%x\n", __func__, unmap.mem_map_handle);
+	rc = q6lsm_apr_send_pkt(client, client->mmap_apr, &unmap, true,
+				NULL);
+	if (rc)
+		pr_err("%s: Failed mmap_regions opcode 0x%x rc %d\n",
+		       __func__, unmap.hdr.opcode, rc);
+
+	return rc;
+}
+
 static int q6lsm_send_cal(struct lsm_client *client)
 {
 	int rc;
@@ -557,15 +589,20 @@
 	/* Cache mmap address, only map once or if new addr */
 	if ((lsm_common.lsm_cal_addr != lsm_cal.cal_paddr) ||
 	    (lsm_cal.cal_size > lsm_common.lsm_cal_size)) {
-		if (lsm_common.lsm_cal_addr != 0)
-			afe_cmd_memory_unmap(lsm_cal.cal_paddr);
+		if (lsm_common.lsm_cal_addr != 0) {
+			rc = q6lsm_memory_unmap_regions(client,
+						lsm_common.mmap_handle_for_cal);
+			if (rc)
+				pr_warn("%s: Unmapping %x failed, %d\n",
+					__func__, lsm_common.lsm_cal_addr, rc);
+		}
 
 		rc = q6lsm_memory_map_regions(client, lsm_cal.cal_paddr,
 					      LSM_CAL_SIZE,
 					      &lsm_common.mmap_handle_for_cal);
 		if (rc < 0) {
-			pr_err("%s: Calibration data memory map failed\n",
-			       __func__);
+			pr_err("%s: Calibration data memory map failed, %d\n",
+			       __func__, rc);
 			goto bail;
 		}
 		lsm_common.lsm_cal_addr = lsm_cal.cal_paddr;
@@ -589,38 +626,18 @@
 	return rc;
 }
 
-static int q6lsm_memory_unmap_regions(struct lsm_client *client)
-{
-	struct avs_cmd_shared_mem_unmap_regions unmap;
-	int rc = 0;
-	int cmd_size = 0;
-
-	cmd_size = sizeof(struct avs_cmd_shared_mem_unmap_regions);
-	q6lsm_add_mmaphdr(client, &unmap.hdr, cmd_size,
-			  true, (client->session << 8));
-	unmap.hdr.opcode = LSM_SESSION_CMD_SHARED_MEM_UNMAP_REGIONS;
-	unmap.mem_map_handle = client->sound_model.mem_map_handle;
-
-	pr_debug("%s: unmap handle 0x%x\n", __func__, unmap.mem_map_handle);
-	rc = q6lsm_apr_send_pkt(client, client->mmap_apr, &unmap, true,
-				NULL);
-	if (rc)
-		pr_err("%s: Failed mmap_regions opcode 0x%x rc %d\n",
-		       __func__, unmap.hdr.opcode, rc);
-
-	return rc;
-}
-
-static int q6lsm_snd_model_buf_free(struct lsm_client *client)
+int q6lsm_snd_model_buf_free(struct lsm_client *client)
 {
 	int rc;
 
 	pr_debug("%s: Session id %d\n", __func__, client->session);
 	mutex_lock(&client->cmd_lock);
-	rc = q6lsm_memory_unmap_regions(client);
-	if (rc < 0) {
+	rc = q6lsm_memory_unmap_regions(client,
+					client->sound_model.mem_map_handle);
+	if (rc < 0)
 		pr_err("%s CMD Memory_unmap_regions failed\n", __func__);
-	} else if (client->sound_model.data) {
+
+	if (client->sound_model.data) {
 		ion_unmap_kernel(client->sound_model.client,
 				 client->sound_model.handle);
 		ion_free(client->sound_model.client,
@@ -666,6 +683,7 @@
 		pr_debug("%s: SSR event received 0x%x, event 0x%x, proc 0x%x\n",
 			 __func__, data->opcode, data->reset_event,
 			 data->reset_proc);
+		lsm_common.lsm_cal_addr = 0;
 		return 0;
 	}
 
@@ -726,6 +744,7 @@
 		if (IS_ERR_OR_NULL(client->sound_model.client)) {
 			pr_err("%s: ION create client for AUDIO failed\n",
 			       __func__);
+			mutex_unlock(&client->cmd_lock);
 			goto fail;
 		}
 		client->sound_model.handle =
@@ -734,6 +753,7 @@
 		if (IS_ERR_OR_NULL(client->sound_model.handle)) {
 			pr_err("%s: ION memory allocation for AUDIO failed\n",
 			       __func__);
+			mutex_unlock(&client->cmd_lock);
 			goto fail;
 		}
 
@@ -744,6 +764,7 @@
 		if (rc) {
 			pr_err("%s: ION get physical mem failed, rc%d\n",
 			       __func__, rc);
+			mutex_unlock(&client->cmd_lock);
 			goto fail;
 		}
 
@@ -752,6 +773,7 @@
 				   client->sound_model.handle);
 		if (IS_ERR_OR_NULL(client->sound_model.data)) {
 			pr_err("%s: ION memory mapping failed\n", __func__);
+			mutex_unlock(&client->cmd_lock);
 			goto fail;
 		}
 		memset(client->sound_model.data, 0, len);