Merge "slim_ngd: Use DSP before-shutdown notification for DSP SSR"
diff --git a/drivers/slimbus/slim-msm-ngd.c b/drivers/slimbus/slim-msm-ngd.c
index bca0af0..fd2d0e3 100644
--- a/drivers/slimbus/slim-msm-ngd.c
+++ b/drivers/slimbus/slim-msm-ngd.c
@@ -163,27 +163,51 @@
 	case QMI_SERVER_ARRIVE:
 		schedule_work(&qmi->ssr_up);
 		break;
-	case QMI_SERVER_EXIT:
-		dev->state = MSM_CTRL_DOWN;
-		/* make sure autosuspend is not called until ADSP comes up*/
-		pm_runtime_get_noresume(dev->dev);
-		/* Reset ctrl_up completion */
-		init_completion(&dev->ctrl_up);
-		schedule_work(&qmi->ssr_down);
-		break;
 	default:
 		break;
 	}
 	return 0;
 }
 
+static int dsp_ssr_notify_cb(struct notifier_block *n, unsigned long code,
+				void *_cmd)
+{
+	struct msm_slim_ss *dsp = container_of(n, struct msm_slim_ss, nb);
+	struct msm_slim_ctrl *dev = container_of(dsp, struct msm_slim_ctrl,
+						dsp);
+
+	switch (code) {
+	case SUBSYS_BEFORE_SHUTDOWN:
+		SLIM_INFO(dev, "SLIM DSP SSR notify cb:%lu\n", code);
+		/* wait for current transaction */
+		mutex_lock(&dev->tx_lock);
+		/* make sure autosuspend is not called until ADSP comes up*/
+		pm_runtime_get_noresume(dev->dev);
+		dev->state = MSM_CTRL_DOWN;
+		/* Reset ctrl_up completion */
+		init_completion(&dev->ctrl_up);
+		/* disconnect BAM pipes */
+		if (dev->use_rx_msgqs == MSM_MSGQ_ENABLED)
+			dev->use_rx_msgqs = MSM_MSGQ_DOWN;
+		if (dev->use_tx_msgqs == MSM_MSGQ_ENABLED)
+			dev->use_tx_msgqs = MSM_MSGQ_DOWN;
+		msm_slim_sps_exit(dev, false);
+		schedule_work(&dev->qmi.ssr_down);
+		mutex_unlock(&dev->tx_lock);
+		break;
+	default:
+		break;
+	}
+	return NOTIFY_DONE;
+}
+
 static int mdm_ssr_notify_cb(struct notifier_block *n, unsigned long code,
 				void *_cmd)
 {
 	void __iomem *ngd;
-	struct msm_slim_mdm *mdm = container_of(n, struct msm_slim_mdm, nb);
-	struct msm_slim_ctrl *dev = container_of(mdm, struct msm_slim_ctrl,
-						mdm);
+	struct msm_slim_ss *ext_mdm = container_of(n, struct msm_slim_ss, nb);
+	struct msm_slim_ctrl *dev = container_of(ext_mdm, struct msm_slim_ctrl,
+						ext_mdm);
 	struct slim_controller *ctrl = &dev->ctrl;
 	u32 laddr;
 	struct slim_device *sbdev;
@@ -198,11 +222,11 @@
 		 * handover later
 		 */
 		msm_slim_qmi_check_framer_request(dev);
-		dev->mdm.state = MSM_CTRL_DOWN;
+		dev->ext_mdm.state = MSM_CTRL_DOWN;
 		msm_slim_put_ctrl(dev);
 		break;
 	case SUBSYS_AFTER_POWERUP:
-		if (dev->mdm.state != MSM_CTRL_DOWN)
+		if (dev->ext_mdm.state != MSM_CTRL_DOWN)
 			return NOTIFY_DONE;
 		SLIM_INFO(dev,
 			"SLIM %lu external_modem SSR notify cb\n", code);
@@ -213,10 +237,12 @@
 		ngd = dev->base + NGD_BASE(dev->ctrl.nr, dev->ver);
 		laddr = readl_relaxed(ngd + NGD_STATUS);
 		if (!(laddr & NGD_LADDR)) {
+			mutex_lock(&dev->tx_lock);
 			/* runtime-pm state should be consistent with HW */
 			pm_runtime_disable(dev->dev);
 			pm_runtime_set_suspended(dev->dev);
 			dev->state = MSM_CTRL_DOWN;
+			mutex_unlock(&dev->tx_lock);
 			SLIM_INFO(dev,
 				"SLIM MDM SSR (active framer on MDM) dev-down\n");
 			list_for_each_entry(sbdev, &ctrl->devs, dev_list)
@@ -225,7 +251,7 @@
 			pm_runtime_set_active(dev->dev);
 			pm_runtime_enable(dev->dev);
 		}
-		dev->mdm.state = MSM_CTRL_AWAKE;
+		dev->ext_mdm.state = MSM_CTRL_AWAKE;
 		msm_slim_put_ctrl(dev);
 		break;
 	default:
@@ -286,6 +312,7 @@
 	bool report_sat = false;
 	bool sync_wr = true;
 
+	mutex_lock(&dev->tx_lock);
 	if (txn->mc == SLIM_USR_MC_REPORT_SATELLITE &&
 		txn->mt == SLIM_MSG_MT_SRC_REFERRED_USER)
 		report_sat = true;
@@ -298,6 +325,7 @@
 		 * If the state was DOWN, SSR UP notification will take
 		 * care of putting the device in active state.
 		 */
+		mutex_unlock(&dev->tx_lock);
 		ret = ngd_slim_runtime_resume(dev->dev);
 
 		if (ret) {
@@ -307,17 +335,24 @@
 		}
 	}
 
-	else if (txn->mc & SLIM_MSG_CLK_PAUSE_SEQ_FLG)
+	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;
 	}
+
 	/* If txn is tried when controller is down, wait for ADSP to boot */
 	if (!report_sat) {
-		if (dev->state == MSM_CTRL_DOWN) {
+		enum msm_ctrl_state cur_state = dev->state;
+
+		mutex_unlock(&dev->tx_lock);
+		if (cur_state == MSM_CTRL_DOWN) {
 			u8 mc = (u8)txn->mc;
 			int timeout;
 			SLIM_INFO(dev, "ADSP slimbus not up yet\n");
@@ -359,27 +394,29 @@
 				return -EREMOTEIO;
 			timeout = wait_for_completion_timeout(&dev->ctrl_up,
 							HZ);
-			if (!timeout && dev->state == MSM_CTRL_DOWN)
+			if (!timeout)
 				return -ETIMEDOUT;
 		}
 		ret = msm_slim_get_ctrl(dev);
+		mutex_lock(&dev->tx_lock);
 		/*
 		 * Runtime-pm's callbacks are not called until runtime-pm's
 		 * error status is cleared
 		 * Setting runtime status to suspended clears the error
 		 * It also makes HW status cosistent with what SW has it here
 		 */
-		if (pm_runtime_enabled(dev->dev) && ret < 0) {
+		if ((pm_runtime_enabled(dev->dev) && ret < 0) ||
+				dev->state == MSM_CTRL_DOWN) {
 			SLIM_ERR(dev, "slim ctrl vote failed ret:%d, state:%d",
 					ret, dev->state);
 			pm_runtime_set_suspended(dev->dev);
+			mutex_unlock(&dev->tx_lock);
 			msm_slim_put_ctrl(dev);
 			return -EREMOTEIO;
 		} else {
 			dev->state = MSM_CTRL_AWAKE;
 		}
 	}
-	mutex_lock(&dev->tx_lock);
 
 	if (txn->mt == SLIM_MSG_MT_CORE &&
 		(txn->mc == SLIM_MSG_MC_CONNECT_SOURCE ||
@@ -413,12 +450,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;
 		}
@@ -538,9 +575,11 @@
 			 * transactions don't timeout due to unavailable
 			 * descriptors
 			 */
-			msm_slim_disconnect_endp(dev, &dev->tx_msgq,
-						&dev->use_tx_msgqs);
-			msm_slim_connect_endp(dev, &dev->tx_msgq, NULL);
+			if (dev->state != MSM_CTRL_DOWN) {
+				msm_slim_disconnect_endp(dev, &dev->tx_msgq,
+							&dev->use_tx_msgqs);
+				msm_slim_connect_endp(dev, &dev->tx_msgq, NULL);
+			}
 		} else {
 			ret = dev->err;
 		}
@@ -1227,12 +1266,6 @@
 	struct slim_device *sbdev;
 
 	ngd_slim_enable(dev, false);
-	/* disconnect BAM pipes */
-	if (dev->use_rx_msgqs == MSM_MSGQ_ENABLED)
-		dev->use_rx_msgqs = MSM_MSGQ_DOWN;
-	if (dev->use_tx_msgqs == MSM_MSGQ_ENABLED)
-		dev->use_tx_msgqs = MSM_MSGQ_DOWN;
-	msm_slim_sps_exit(dev, false);
 	/* device up should be called again after SSR */
 	list_for_each_entry(sbdev, &ctrl->devs, dev_list)
 		slim_report_absent(sbdev);
@@ -1442,14 +1475,21 @@
 	pm_runtime_set_suspended(dev->dev);
 	pm_runtime_enable(dev->dev);
 
+	dev->dsp.nb.notifier_call = dsp_ssr_notify_cb;
+	dev->dsp.ssr = subsys_notif_register_notifier("adsp",
+						&dev->dsp.nb);
+	if (IS_ERR_OR_NULL(dev->dsp.ssr))
+		dev_err(dev->dev,
+			"subsys_notif_register_notifier failed %p",
+			dev->dsp.ssr);
 	if (slim_mdm) {
-		dev->mdm.nb.notifier_call = mdm_ssr_notify_cb;
-		dev->mdm.ssr = subsys_notif_register_notifier(ext_modem_id,
-							&dev->mdm.nb);
-		if (IS_ERR_OR_NULL(dev->mdm.ssr))
+		dev->ext_mdm.nb.notifier_call = mdm_ssr_notify_cb;
+		dev->ext_mdm.ssr = subsys_notif_register_notifier(ext_modem_id,
+							&dev->ext_mdm.nb);
+		if (IS_ERR_OR_NULL(dev->ext_mdm.ssr))
 			dev_err(dev->dev,
 				"subsys_notif_register_notifier failed %p",
-				dev->mdm.ssr);
+				dev->ext_mdm.ssr);
 	}
 
 	INIT_WORK(&dev->qmi.ssr_down, ngd_adsp_down);
@@ -1507,8 +1547,12 @@
 				SLIMBUS_QMI_SVC_V1,
 				SLIMBUS_QMI_INS_ID, &dev->qmi.nb);
 	pm_runtime_disable(&pdev->dev);
-	if (!IS_ERR_OR_NULL(dev->mdm.ssr))
-		subsys_notif_unregister_notifier(dev->mdm.ssr, &dev->mdm.nb);
+	if (!IS_ERR_OR_NULL(dev->dsp.ssr))
+		subsys_notif_unregister_notifier(dev->dsp.ssr,
+						&dev->dsp.nb);
+	if (!IS_ERR_OR_NULL(dev->ext_mdm.ssr))
+		subsys_notif_unregister_notifier(dev->ext_mdm.ssr,
+						&dev->ext_mdm.nb);
 	free_irq(dev->irq, dev);
 	slim_del_controller(&dev->ctrl);
 	kthread_stop(dev->rx_msgq_thread);
diff --git a/drivers/slimbus/slim-msm.c b/drivers/slimbus/slim-msm.c
index 11741b8..c3f371c 100644
--- a/drivers/slimbus/slim-msm.c
+++ b/drivers/slimbus/slim-msm.c
@@ -951,10 +951,16 @@
 
 void msm_slim_sps_exit(struct msm_slim_ctrl *dev, bool dereg)
 {
+	int i;
+
 	if (dev->use_rx_msgqs >= MSM_MSGQ_ENABLED)
 		msm_slim_remove_ep(dev, &dev->rx_msgq, &dev->use_rx_msgqs);
 	if (dev->use_tx_msgqs >= MSM_MSGQ_ENABLED)
 		msm_slim_remove_ep(dev, &dev->tx_msgq, &dev->use_tx_msgqs);
+	for (i = dev->port_b; i < MSM_SLIM_NPORTS; i++) {
+		if (dev->pipes[i - dev->port_b].connected)
+			msm_slim_disconn_pipe_port(dev, i - dev->port_b);
+	}
 	if (dereg) {
 		int i;
 		for (i = dev->port_b; i < MSM_SLIM_NPORTS; i++) {
diff --git a/drivers/slimbus/slim-msm.h b/drivers/slimbus/slim-msm.h
index 5f12f24..99297a9 100644
--- a/drivers/slimbus/slim-msm.h
+++ b/drivers/slimbus/slim-msm.h
@@ -214,7 +214,7 @@
 	struct work_struct		ssr_up;
 };
 
-struct msm_slim_mdm {
+struct msm_slim_ss {
 	struct notifier_block nb;
 	void *ssr;
 	enum msm_ctrl_state state;
@@ -269,7 +269,8 @@
 	u32			ver;
 	struct msm_slim_qmi	qmi;
 	struct msm_slim_pdata	pdata;
-	struct msm_slim_mdm	mdm;
+	struct msm_slim_ss	ext_mdm;
+	struct msm_slim_ss	dsp;
 	int			default_ipc_log_mask;
 	int			ipc_log_mask;
 	bool			sysfs_created;