qcacld-3.0: Introduce SSR protection wrapper to IPA callback APIs

IPA driver calling WLAN driver callback, and in parallel WLAN
driver is unloading and freeing this callback, which leads to
a use after free scenario

Add SSR protection wrapper to all of IPA callback APIs in driver
to avoid racing against driver unload or SSR or self recovery

Change-Id: I5dcdfe4749b89104ec79eac060e60fe5aa7c2335
Crs-Fixed: 2307365
diff --git a/components/ipa/core/inc/wlan_ipa_core.h b/components/ipa/core/inc/wlan_ipa_core.h
index 25eb583..f3cbd5b 100644
--- a/components/ipa/core/inc/wlan_ipa_core.h
+++ b/components/ipa/core/inc/wlan_ipa_core.h
@@ -322,8 +322,8 @@
 				  struct op_msg_type *op_msg);
 
 /**
- * wlan_ipa_wdi_meter_notifier_cb() - WLAN to IPA callback handler.
- * IPA calls to get WLAN stats or set quota limit.
+ * wlan_ipa_wdi_meter_notifier_cb() - SSR wrapper for
+ * __wlan_ipa_wdi_meter_notifier_cb
  * @priv: pointer to private data registered with IPA (we register a
  *        pointer to the global IPA context)
  * @evt: the IPA event which triggered the callback
@@ -332,7 +332,7 @@
  * Return: None
  */
 void wlan_ipa_wdi_meter_notifier_cb(qdf_ipa_wdi_meter_evt_type_t evt,
-				   void *data);
+				    void *data);
 
 /**
  * wlan_ipa_init_metering() - IPA metering stats completion event reset
diff --git a/components/ipa/core/src/wlan_ipa_core.c b/components/ipa/core/src/wlan_ipa_core.c
index 3d79cc3..542c70c 100644
--- a/components/ipa/core/src/wlan_ipa_core.c
+++ b/components/ipa/core/src/wlan_ipa_core.c
@@ -743,7 +743,7 @@
 }
 
 /**
- * wlan_ipa_w2i_cb() - WLAN to IPA callback handler
+ * __wlan_ipa_w2i_cb() - WLAN to IPA callback handler
  * @priv: pointer to private data registered with IPA (we register a
  *	pointer to the global IPA context)
  * @evt: the IPA event which triggered the callback
@@ -751,8 +751,8 @@
  *
  * Return: None
  */
-static void wlan_ipa_w2i_cb(void *priv, qdf_ipa_dp_evt_type_t evt,
-			    unsigned long data)
+static void __wlan_ipa_w2i_cb(void *priv, qdf_ipa_dp_evt_type_t evt,
+			      unsigned long data)
 {
 	struct wlan_ipa_priv *ipa_ctx = NULL;
 	qdf_nbuf_t skb;
@@ -761,6 +761,11 @@
 	struct wlan_ipa_iface_context *iface_context;
 	uint8_t fw_desc;
 
+	if (qdf_is_module_state_transitioning()) {
+		ipa_err("Module transition in progress");
+		return;
+	}
+
 	ipa_ctx = (struct wlan_ipa_priv *)priv;
 
 	if (!ipa_ctx)
@@ -834,7 +839,24 @@
 }
 
 /**
- * wlan_ipa_i2w_cb() - IPA to WLAN callback
+ * wlan_ipa_w2i_cb() - SSR wrapper for __wlan_ipa_w2i_cb
+ * @priv: pointer to private data registered with IPA (we register a
+ *	pointer to the global IPA context)
+ * @evt: the IPA event which triggered the callback
+ * @data: data associated with the event
+ *
+ * Return: None
+ */
+static void wlan_ipa_w2i_cb(void *priv, qdf_ipa_dp_evt_type_t evt,
+			    unsigned long data)
+{
+	qdf_ssr_protect(__func__);
+	__wlan_ipa_w2i_cb(priv, evt, data);
+	qdf_ssr_unprotect(__func__);
+}
+
+/**
+ * __wlan_ipa_i2w_cb() - IPA to WLAN callback
  * @priv: pointer to private data registered with IPA (we register a
  *	pointer to the interface-specific IPA context)
  * @evt: the IPA event which triggered the callback
@@ -842,8 +864,8 @@
  *
  * Return: None
  */
-static void wlan_ipa_i2w_cb(void *priv, qdf_ipa_dp_evt_type_t evt,
-			     unsigned long data)
+static void __wlan_ipa_i2w_cb(void *priv, qdf_ipa_dp_evt_type_t evt,
+			      unsigned long data)
 {
 	struct wlan_ipa_priv *ipa_ctx = NULL;
 	qdf_ipa_rx_data_t *ipa_tx_desc;
@@ -851,6 +873,11 @@
 	qdf_nbuf_t skb;
 	struct wlan_ipa_pm_tx_cb *pm_tx_cb = NULL;
 
+	if (qdf_is_module_state_transitioning()) {
+		ipa_err("Module transition in progress");
+		return;
+	}
+
 	iface_context = (struct wlan_ipa_iface_context *)priv;
 	ipa_tx_desc = (qdf_ipa_rx_data_t *)data;
 	ipa_ctx = iface_context->ipa_ctx;
@@ -903,6 +930,23 @@
 	return wlan_ipa_send_pkt_to_tl(iface_context, ipa_tx_desc);
 }
 
+/**
+ * wlan_ipa_i2w_cb() - IPA to WLAN callback
+ * @priv: pointer to private data registered with IPA (we register a
+ *	pointer to the interface-specific IPA context)
+ * @evt: the IPA event which triggered the callback
+ * @data: data associated with the event
+ *
+ * Return: None
+ */
+static void wlan_ipa_i2w_cb(void *priv, qdf_ipa_dp_evt_type_t evt,
+			    unsigned long data)
+{
+	qdf_ssr_protect(__func__);
+	__wlan_ipa_i2w_cb(priv, evt, data);
+	qdf_ssr_unprotect(__func__);
+}
+
 QDF_STATUS wlan_ipa_suspend(struct wlan_ipa_priv *ipa_ctx)
 {
 	/*
@@ -2674,18 +2718,23 @@
 }
 
 /**
- * wlan_ipa_uc_fw_op_event_handler - IPA uC FW OPvent handler
- * @work: uC OP work
+ * __wlan_ipa_uc_fw_op_event_handler - IPA uC FW OPvent handler
+ * @data: uC OP work
  *
  * Return: None
  */
-static void wlan_ipa_uc_fw_op_event_handler(void *data)
+static void __wlan_ipa_uc_fw_op_event_handler(void *data)
 {
 	struct op_msg_type *msg;
 	struct uc_op_work_struct *uc_op_work =
 				(struct uc_op_work_struct *)data;
 	struct wlan_ipa_priv *ipa_ctx = gp_ipa;
 
+	if (qdf_is_module_state_transitioning()) {
+		ipa_err("Module transition in progress");
+		return;
+	}
+
 	msg = uc_op_work->msg;
 	uc_op_work->msg = NULL;
 	ipa_debug("posted msg %d", msg->op_code);
@@ -2694,6 +2743,20 @@
 }
 
 /**
+ * wlan_ipa_uc_fw_op_event_handler - SSR wrapper for
+ * __wlan_ipa_uc_fw_op_event_handler
+ * @data: uC OP work
+ *
+ * Return: None
+ */
+static void wlan_ipa_uc_fw_op_event_handler(void *data)
+{
+	qdf_ssr_protect(__func__);
+	__wlan_ipa_uc_fw_op_event_handler(data);
+	qdf_ssr_unprotect(__func__);
+}
+
+/**
  * wlan_ipa_uc_op_event_handler() - IPA UC OP event handler
  * @op_msg: operation message received from firmware
  * @ipa_ctx: Global IPA context
diff --git a/components/ipa/core/src/wlan_ipa_stats.c b/components/ipa/core/src/wlan_ipa_stats.c
index 5a25430..48bb51a 100644
--- a/components/ipa/core/src/wlan_ipa_stats.c
+++ b/components/ipa/core/src/wlan_ipa_stats.c
@@ -20,6 +20,7 @@
 #include "wlan_ipa_main.h"
 #include "wlan_ipa_core.h"
 #include "cdp_txrx_ipa.h"
+#include "qdf_platform.h"
 
 /**
  * wlan_ipa_uc_rt_debug_host_fill - fill rt debug buffer
@@ -845,7 +846,7 @@
 }
 
 /**
- * wlan_ipa_wdi_meter_notifier_cb() - WLAN to IPA callback handler.
+ * __wlan_ipa_wdi_meter_notifier_cb() - WLAN to IPA callback handler.
  * IPA calls to get WLAN stats or set quota limit.
  * @priv: pointer to private data registered with IPA (we register a
  *	  pointer to the IPA context)
@@ -854,8 +855,8 @@
  *
  * Return: None
  */
-void wlan_ipa_wdi_meter_notifier_cb(qdf_ipa_wdi_meter_evt_type_t evt,
-				    void *data)
+static void __wlan_ipa_wdi_meter_notifier_cb(qdf_ipa_wdi_meter_evt_type_t evt,
+					     void *data)
 {
 	struct wlan_ipa_priv *ipa_ctx = wlan_ipa_get_obj_context();
 	struct wlan_ipa_iface_context *iface_ctx;
@@ -865,6 +866,11 @@
 
 	ipa_debug("event=%d", evt);
 
+	if (qdf_is_module_state_transitioning()) {
+		ipa_err("Module transition in progress");
+		return;
+	}
+
 	iface_ctx = wlan_ipa_get_iface(ipa_ctx, QDF_STA_MODE);
 	if (!iface_ctx) {
 		ipa_err("IPA uC share stats failed - no iface");
@@ -937,4 +943,23 @@
 		break;
 	}
 }
+
+/**
+ * wlan_ipa_wdi_meter_notifier_cb() - SSR wrapper for
+ * __wlan_ipa_wdi_meter_notifier_cb
+ * @priv: pointer to private data registered with IPA (we register a
+ *	  pointer to the IPA context)
+ * @evt: the IPA event which triggered the callback
+ * @data: data associated with the event
+ *
+ * Return: None
+ */
+void wlan_ipa_wdi_meter_notifier_cb(qdf_ipa_wdi_meter_evt_type_t evt,
+				    void *data)
+{
+	qdf_ssr_protect(__func__);
+	__wlan_ipa_wdi_meter_notifier_cb(evt, data);
+	qdf_ssr_unprotect(__func__);
+}
+
 #endif /* FEATURE_METERING */