slim_ngd: Ensure device state consistency with runtime-pm during SSR

During ADSP SSR, client's thread calling runtime-pm resume will
fail since ADSP is unreachable. Make sure such power-up/resume attempt
is blocked until ADSP comes up by using mutex during device-state
transition.

Change-Id: Ie85e52bb2974aaee9654eb8fa1cc60fe37c61b75
Signed-off-by: Sagar Dharia <sdharia@codeaurora.org>
diff --git a/drivers/slimbus/slim-msm-ngd.c b/drivers/slimbus/slim-msm-ngd.c
index fd2d0e3..f3a886b 100644
--- a/drivers/slimbus/slim-msm-ngd.c
+++ b/drivers/slimbus/slim-msm-ngd.c
@@ -247,7 +247,7 @@
 				"SLIM MDM SSR (active framer on MDM) dev-down\n");
 			list_for_each_entry(sbdev, &ctrl->devs, dev_list)
 				slim_report_absent(sbdev);
-			ngd_slim_power_up(dev, true);
+			ngd_slim_runtime_resume(dev->dev);
 			pm_runtime_set_active(dev->dev);
 			pm_runtime_enable(dev->dev);
 		}
@@ -312,12 +312,22 @@
 	bool report_sat = false;
 	bool sync_wr = true;
 
-	mutex_lock(&dev->tx_lock);
+	if (txn->mc & SLIM_MSG_CLK_PAUSE_SEQ_FLG)
+		return -EPROTONOSUPPORT;
+
+	if (txn->mt == SLIM_MSG_MT_CORE &&
+		(txn->mc >= SLIM_MSG_MC_BEGIN_RECONFIGURATION &&
+		 txn->mc <= SLIM_MSG_MC_RECONFIGURE_NOW))
+		return 0;
+
 	if (txn->mc == SLIM_USR_MC_REPORT_SATELLITE &&
 		txn->mt == SLIM_MSG_MT_SRC_REFERRED_USER)
 		report_sat = true;
-	if (!pm_runtime_enabled(dev->dev) && dev->state == MSM_CTRL_ASLEEP &&
-			report_sat == false) {
+	else
+		mutex_lock(&dev->tx_lock);
+
+	if (!report_sat && !pm_runtime_enabled(dev->dev) &&
+			dev->state == MSM_CTRL_ASLEEP) {
 		/*
 		 * Counter-part of system-suspend when runtime-pm is not enabled
 		 * This way, resume can be left empty and device will be put in
@@ -333,28 +343,16 @@
 					ret, dev->state);
 			return -EREMOTEIO;
 		}
-	}
-
-	else if (txn->mc & SLIM_MSG_CLK_PAUSE_SEQ_FLG) {
-		mutex_unlock(&dev->tx_lock);
-		return -EPROTONOSUPPORT;
-	}
-
-	if (txn->mt == SLIM_MSG_MT_CORE &&
-		(txn->mc >= SLIM_MSG_MC_BEGIN_RECONFIGURATION &&
-		 txn->mc <= SLIM_MSG_MC_RECONFIGURE_NOW)) {
-		mutex_unlock(&dev->tx_lock);
-		return 0;
+		mutex_lock(&dev->tx_lock);
 	}
 
 	/* If txn is tried when controller is down, wait for ADSP to boot */
 	if (!report_sat) {
-		enum msm_ctrl_state cur_state = dev->state;
 
-		mutex_unlock(&dev->tx_lock);
-		if (cur_state == MSM_CTRL_DOWN) {
+		if (dev->state == MSM_CTRL_DOWN) {
 			u8 mc = (u8)txn->mc;
 			int timeout;
+			mutex_unlock(&dev->tx_lock);
 			SLIM_INFO(dev, "ADSP slimbus not up yet\n");
 			/*
 			 * Messages related to data channel management can't
@@ -396,7 +394,10 @@
 							HZ);
 			if (!timeout)
 				return -ETIMEDOUT;
+			mutex_lock(&dev->tx_lock);
 		}
+
+		mutex_unlock(&dev->tx_lock);
 		ret = msm_slim_get_ctrl(dev);
 		mutex_lock(&dev->tx_lock);
 		/*
@@ -413,8 +414,6 @@
 			mutex_unlock(&dev->tx_lock);
 			msm_slim_put_ctrl(dev);
 			return -EREMOTEIO;
-		} else {
-			dev->state = MSM_CTRL_AWAKE;
 		}
 	}
 
@@ -450,12 +449,12 @@
 				SLIM_DBG(dev, "SLIM PGD LA:0x%x, ret:%d\n",
 					dev->pgdla, ret);
 				if (ret) {
-					mutex_unlock(&dev->tx_lock);
 					SLIM_ERR(dev,
 						"Incorrect SLIM-PGD EAPC:0x%x\n",
 							dev->pdata.eapc);
 					return ret;
 				}
+				mutex_lock(&dev->tx_lock);
 			}
 			txn->la = dev->pgdla;
 		}
@@ -624,9 +623,10 @@
 		return ret ? ret : dev->err;
 	}
 ngd_xfer_err:
-	mutex_unlock(&dev->tx_lock);
-	if (!report_sat)
+	if (!report_sat) {
+		mutex_unlock(&dev->tx_lock);
 		msm_slim_put_ctrl(dev);
+	}
 	return ret ? ret : dev->err;
 }
 
@@ -935,7 +935,6 @@
 			enum msm_ctrl_state prev_state = dev->state;
 			SLIM_INFO(dev,
 				"SLIM SAT: capability exchange successful\n");
-			dev->state = MSM_CTRL_AWAKE;
 			if (prev_state >= MSM_CTRL_ASLEEP)
 				complete(&dev->reconf);
 			else
@@ -1019,8 +1018,10 @@
 	if (!mdm_restart && cur_state == MSM_CTRL_DOWN) {
 		int timeout = wait_for_completion_timeout(&dev->qmi.qmi_comp,
 						HZ);
-		if (!timeout)
+		if (!timeout) {
 			SLIM_ERR(dev, "slimbus QMI init timed out\n");
+			return -EREMOTEIO;
+		}
 	}
 
 	/* No need to vote if contorller is not in low power mode */
@@ -1107,11 +1108,11 @@
 		SLIM_ERR(dev, "Failed to receive master capability\n");
 		return -ETIMEDOUT;
 	}
-	if (cur_state == MSM_CTRL_DOWN) {
-		complete(&dev->ctrl_up);
-		/* Resetting the log level */
-		SLIM_RST_LOGLVL(dev);
-	}
+	/* mutliple transactions waiting on slimbus to power up? */
+	if (cur_state == MSM_CTRL_DOWN)
+		complete_all(&dev->ctrl_up);
+	/* Resetting the log level */
+	SLIM_RST_LOGLVL(dev);
 	return 0;
 }
 
@@ -1568,8 +1569,10 @@
 {
 	struct platform_device *pdev = to_platform_device(device);
 	struct msm_slim_ctrl *dev = platform_get_drvdata(pdev);
+	mutex_lock(&dev->tx_lock);
 	if (dev->state == MSM_CTRL_AWAKE)
 		dev->state = MSM_CTRL_IDLE;
+	mutex_unlock(&dev->tx_lock);
 	dev_dbg(device, "pm_runtime: idle...\n");
 	pm_request_autosuspend(device);
 	return -EAGAIN;
@@ -1586,6 +1589,7 @@
 	struct platform_device *pdev = to_platform_device(device);
 	struct msm_slim_ctrl *dev = platform_get_drvdata(pdev);
 	int ret = 0;
+	mutex_lock(&dev->tx_lock);
 	if (dev->state >= MSM_CTRL_ASLEEP)
 		ret = ngd_slim_power_up(dev, false);
 	if (ret) {
@@ -1597,6 +1601,7 @@
 	} else {
 		dev->state = MSM_CTRL_AWAKE;
 	}
+	mutex_unlock(&dev->tx_lock);
 	SLIM_INFO(dev, "Slim runtime resume: ret %d\n", ret);
 	return ret;
 }
@@ -1607,6 +1612,7 @@
 	struct platform_device *pdev = to_platform_device(device);
 	struct msm_slim_ctrl *dev = platform_get_drvdata(pdev);
 	int ret = 0;
+	mutex_lock(&dev->tx_lock);
 	ret = ngd_slim_power_down(dev);
 	if (ret) {
 		if (ret != -EBUSY)
@@ -1615,6 +1621,7 @@
 	} else {
 		dev->state = MSM_CTRL_ASLEEP;
 	}
+	mutex_unlock(&dev->tx_lock);
 	SLIM_INFO(dev, "Slim runtime suspend: ret %d\n", ret);
 	return ret;
 }