qcacmn: Use suspend_noirq callback instead of disabling irqs

Disabling the interrupts and setting them as wakeup sources does
not work as expected.  The pending interrupt gets trapped in sw
and kernel does not check for it before finishing the suspend.

Instead, use the suspend_noirq callback to guarantee that
wakeup messages don't get processed without rejecting the suspend.

Change-Id: I5ec5ce2a7e1b14c3d8477fe7aa0372c9ffd4dc0d
CRs-Fixed: 1060880
diff --git a/hif/inc/hif.h b/hif/inc/hif.h
index 5b24ef8..9e6ddb4 100644
--- a/hif/inc/hif.h
+++ b/hif/inc/hif.h
@@ -573,6 +573,8 @@
 
 int hif_bus_resume(struct hif_opaque_softc *);
 int hif_bus_suspend(struct hif_opaque_softc *);
+int hif_bus_resume_noirq(struct hif_opaque_softc *);
+int hif_bus_suspend_noirq(struct hif_opaque_softc *);
 
 #ifdef FEATURE_RUNTIME_PM
 int hif_pre_runtime_suspend(struct hif_opaque_softc *hif_ctx);
diff --git a/hif/src/dispatcher/dummy.c b/hif/src/dispatcher/dummy.c
index e9362f9..1690e05 100644
--- a/hif/src/dispatcher/dummy.c
+++ b/hif/src/dispatcher/dummy.c
@@ -84,6 +84,34 @@
 }
 
 /**
+ * hif_dummy_suspend_noirq() - suspend the bus
+ * @hif_ctx: hif context
+ *
+ * dummy for busses that don't need to syncronize
+ * with interrupt disable.
+ *
+ * Return: 0 for success and non-zero for failure
+ */
+int hif_dummy_bus_suspend_noirq(struct hif_softc *hif_ctx)
+{
+	return 0;
+}
+
+/**
+ * hif_dummy_resume_noirq() - resume the bus
+ * @hif_ctx: hif context
+ *
+ * dummy for busses that don't need to syncronize
+ * with interrupt disable.
+ *
+ * Return: 0 for success and non-zero for failure
+ */
+int hif_dummy_bus_resume_noirq(struct hif_softc *hif_ctx)
+{
+	return 0;
+}
+
+/**
  * hif_dummy_target_sleep_state_adjust() - api to adjust state of target
  * @scn: hif context
  * @sleep_ok: allow or deny target to go to sleep
diff --git a/hif/src/dispatcher/dummy.h b/hif/src/dispatcher/dummy.h
index 049fa1a..b531c1d 100644
--- a/hif/src/dispatcher/dummy.h
+++ b/hif/src/dispatcher/dummy.h
@@ -30,6 +30,8 @@
 void hif_dummy_reset_soc(struct hif_softc *scn);
 int hif_dummy_bus_suspend(struct hif_softc *hif_ctx);
 int hif_dummy_bus_resume(struct hif_softc *hif_ctx);
+int hif_dummy_bus_suspend_noirq(struct hif_softc *hif_ctx);
+int hif_dummy_bus_resume_noirq(struct hif_softc *hif_ctx);
 int hif_dummy_target_sleep_state_adjust(struct hif_softc *scn,
 					bool sleep_ok, bool wait_for_it);
 void hif_dummy_enable_power_management(struct hif_softc *hif_ctx,
diff --git a/hif/src/dispatcher/multibus.c b/hif/src/dispatcher/multibus.c
index 416d997..5643b6f 100644
--- a/hif/src/dispatcher/multibus.c
+++ b/hif/src/dispatcher/multibus.c
@@ -55,8 +55,10 @@
 		&hif_dummy_display_stats;
 	bus_ops->hif_clear_stats =
 		&hif_dummy_clear_stats;
-	bus_ops->hif_set_bundle_mode = hif_dummy_set_bundle_mode;
-	bus_ops->hif_bus_reset_resume = hif_dummy_bus_reset_resume;
+	bus_ops->hif_set_bundle_mode = &hif_dummy_set_bundle_mode;
+	bus_ops->hif_bus_reset_resume = &hif_dummy_bus_reset_resume;
+	bus_ops->hif_bus_suspend_noirq = &hif_dummy_bus_suspend_noirq;
+	bus_ops->hif_bus_resume_noirq = &hif_dummy_bus_resume_noirq;
 }
 
 #define NUM_OPS (sizeof(struct hif_bus_ops) / sizeof(void *))
@@ -195,6 +197,18 @@
 	return hif_sc->bus_ops.hif_bus_resume(hif_sc);
 }
 
+int hif_bus_suspend_noirq(struct hif_opaque_softc *hif_ctx)
+{
+	struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_ctx);
+	return hif_sc->bus_ops.hif_bus_suspend_noirq(hif_sc);
+}
+
+int hif_bus_resume_noirq(struct hif_opaque_softc *hif_ctx)
+{
+	struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_ctx);
+	return hif_sc->bus_ops.hif_bus_resume_noirq(hif_sc);
+}
+
 int hif_target_sleep_state_adjust(struct hif_softc *hif_sc,
 			      bool sleep_ok, bool wait_for_it)
 {
diff --git a/hif/src/dispatcher/multibus.h b/hif/src/dispatcher/multibus.h
index 71b7a3c..6342363 100644
--- a/hif/src/dispatcher/multibus.h
+++ b/hif/src/dispatcher/multibus.h
@@ -42,6 +42,8 @@
 	void (*hif_reset_soc)(struct hif_softc *hif_sc);
 	int (*hif_bus_suspend)(struct hif_softc *hif_ctx);
 	int (*hif_bus_resume)(struct hif_softc *hif_ctx);
+	int (*hif_bus_suspend_noirq)(struct hif_softc *hif_ctx);
+	int (*hif_bus_resume_noirq)(struct hif_softc *hif_ctx);
 	int (*hif_target_sleep_state_adjust)(struct hif_softc *scn,
 			bool sleep_ok, bool wait_for_it);
 	void (*hif_disable_isr)(struct hif_softc *hif_sc);
diff --git a/hif/src/dispatcher/multibus_snoc.c b/hif/src/dispatcher/multibus_snoc.c
index ae29270..2dc80d6 100644
--- a/hif/src/dispatcher/multibus_snoc.c
+++ b/hif/src/dispatcher/multibus_snoc.c
@@ -47,6 +47,9 @@
 	bus_ops->hif_reset_soc = &hif_dummy_reset_soc;
 	bus_ops->hif_bus_suspend = &hif_snoc_bus_suspend;
 	bus_ops->hif_bus_resume = &hif_snoc_bus_resume;
+	bus_ops->hif_bus_suspend_noirq = &hif_snoc_bus_suspend_noirq;
+	/* snoc_bus_resume_noirq had no side effects, use dummy resume_noirq */
+	bus_ops->hif_bus_resume_noirq = &hif_dummy_bus_resume_noirq;
 	bus_ops->hif_target_sleep_state_adjust =
 		&hif_dummy_target_sleep_state_adjust;
 
diff --git a/hif/src/dispatcher/snoc_api.h b/hif/src/dispatcher/snoc_api.h
index 813171f..06fc43d 100644
--- a/hif/src/dispatcher/snoc_api.h
+++ b/hif/src/dispatcher/snoc_api.h
@@ -32,6 +32,7 @@
 void hif_snoc_close(struct hif_softc *hif_ctx);
 int hif_snoc_bus_suspend(struct hif_softc *hif_ctx);
 int hif_snoc_bus_resume(struct hif_softc *hif_ctx);
+int hif_snoc_bus_suspend_noirq(struct hif_softc *scn);
 void hif_snoc_disable_isr(struct hif_softc *hif_ctx);
 void hif_snoc_nointrs(struct hif_softc *scn);
 QDF_STATUS hif_snoc_enable_bus(struct hif_softc *ol_sc,
diff --git a/hif/src/snoc/if_snoc.c b/hif/src/snoc/if_snoc.c
index 77bc554..201eb7c 100644
--- a/hif/src/snoc/if_snoc.c
+++ b/hif/src/snoc/if_snoc.c
@@ -381,75 +381,6 @@
 }
 
 /**
- * __hif_snoc_irq_state_vote() - enable/disable all the ce interrupts
- * @scn: hif context pointer
- * @enble: true to enable the interrupts false to disable
- *
- * takes care of unwinding partial successes.
- *
- * Return: QDF_STATUS_SUCCESS on success
- */
-
-static QDF_STATUS __hif_snoc_irq_state_vote(struct hif_softc *scn, bool enable)
-{
-	int num_ce = scn->ce_count;
-	int ce_id = 0;
-	int irq;
-
-	while (ce_id < num_ce) {
-		irq = icnss_get_irq(ce_id);
-		if (irq < 0)
-			goto error;
-
-		if (enable)
-			enable_irq(irq);
-		else
-			disable_irq(irq);
-
-		ce_id++;
-	}
-
-	return QDF_STATUS_SUCCESS;
-
-error:
-	HIF_ERROR("%s: failed to map ce to irq", __func__);
-
-	while (--ce_id >= 0) {
-		irq = icnss_get_irq(ce_id);
-		if (irq < 0)
-			continue;
-
-		if (enable)
-			disable_irq(irq);
-		else
-			enable_irq(irq);
-	}
-	return QDF_STATUS_E_FAULT;
-}
-
-/**
- * hif_snoc_enable_irqs() - enable the ce irqs
- * @scn: hif context
- *
- * Return: QDF_STATUS_SUCCESS on success
- */
-static QDF_STATUS hif_snoc_enable_irqs(struct hif_softc *scn)
-{
-	return __hif_snoc_irq_state_vote(scn, true);
-}
-
-/**
- * hif_snoc_enable_irqs() - enable the ce irqs
- * @scn: hif context
- *
- * Return: QDF_STATUS_SUCCESS on success
- */
-static QDF_STATUS hif_snoc_disable_irqs(struct hif_softc *scn)
-{
-	return __hif_snoc_irq_state_vote(scn, false);
-}
-
-/**
  * hif_snoc_bus_suspend() - prepare to suspend the bus
  * @scn: hif context
  *
@@ -463,24 +394,8 @@
 int hif_snoc_bus_suspend(struct hif_softc *scn)
 {
 	if (hif_snoc_setup_wakeup_sources(scn, true) != QDF_STATUS_SUCCESS)
-		goto error;
-
-	if (hif_snoc_disable_irqs(scn) != QDF_STATUS_SUCCESS)
-		goto wakeup_sources;
-
-	if (hif_drain_tasklets(scn) != 0)
-		goto enable_irqs;
+		return -EFAULT;
 	return 0;
-
-enable_irqs:
-	if (hif_snoc_enable_irqs(scn) != QDF_STATUS_SUCCESS)
-		QDF_BUG(0);
-wakeup_sources:
-	if (hif_snoc_setup_wakeup_sources(scn, false) != QDF_STATUS_SUCCESS)
-		QDF_BUG(0);
-error:
-	return -EFAULT;
-
 }
 
 /**
@@ -497,8 +412,22 @@
 	if (hif_snoc_setup_wakeup_sources(scn, false) != QDF_STATUS_SUCCESS)
 		QDF_BUG(0);
 
-	if (hif_snoc_enable_irqs(scn) != QDF_STATUS_SUCCESS)
-		QDF_BUG(0);
-
 	return 0;
 }
+
+/**
+ * hif_snoc_bus_suspend_noirq() - ensure there are no pending transactions
+ * @scn: hif context
+ *
+ * Ensure that if we recieved the wakeup message before the irq
+ * was disabled that the message is pocessed before suspending.
+ *
+ * Return: -EBUSY if we fail to flush the tasklets.
+ */
+int hif_snoc_bus_suspend_noirq(struct hif_softc *scn)
+{
+	if (hif_drain_tasklets(scn) != 0)
+		return -EBUSY;
+	return 0;
+}
+