qcacld-3.0: Add support in driver to do sap restart during SSR

qcacld-2.0 to qcacld-3.0 propagation

Presently, during subsystem restart Host is sending sap restart
indication to framework(via carrier off) to do SAP unload/load.
But SAP restart functionality is removed in framework when the
carrier off event is received, leading SAP fails to come-up
after subsystem restart.

Add support in driver to do SAP restart internally without sending
restart indication to framework, during subsystem restart.
This feature is controlled by ini param 'gEnableSapInternalRestart'
and by default it's enabled.

Change-Id: I76cb73c1887d4d8124cd9a1c29b9aac47642072a
CRs-Fixed: 1105651
diff --git a/core/hdd/src/wlan_hdd_ipa.c b/core/hdd/src/wlan_hdd_ipa.c
index 21c6302..ffde0d6 100644
--- a/core/hdd/src/wlan_hdd_ipa.c
+++ b/core/hdd/src/wlan_hdd_ipa.c
@@ -2333,8 +2333,11 @@
 	qdf_mem_zero(&pipe_out, sizeof(struct ipa_wdi_out_params));
 
 	qdf_list_create(&ipa_ctxt->pending_event, 1000);
-	qdf_mutex_create(&ipa_ctxt->event_lock);
-	qdf_mutex_create(&ipa_ctxt->ipa_lock);
+
+	if (!cds_is_driver_recovering()) {
+		qdf_mutex_create(&ipa_ctxt->event_lock);
+		qdf_mutex_create(&ipa_ctxt->ipa_lock);
+	}
 
 	/* TX PIPE */
 	pipe_in.sys.ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT;
@@ -2694,12 +2697,17 @@
 	struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
 	int idx;
 	struct hdd_ipa_iface_context *iface_context;
+	hdd_context_t *hdd_ctx;
 
-	if ((!hdd_ipa) || (!hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)))
+	if (!hdd_ipa)
+		return 0;
+
+	hdd_ctx = hdd_ipa->hdd_ctx;
+	if (!hdd_ipa_uc_is_enabled(hdd_ctx))
 		return 0;
 
 	/* send disconnect to ipa driver */
-	hdd_ipa_uc_disconnect(hdd_ipa->hdd_ctx);
+	hdd_ipa_uc_disconnect(hdd_ctx);
 
 	/* Clean up HDD IPA interfaces */
 	for (idx = 0; (hdd_ipa->num_iface > 0) &&
@@ -2723,6 +2731,16 @@
 	}
 	qdf_mutex_release(&hdd_ipa->ipa_lock);
 
+	HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
+		    "%s: Disconnect TX PIPE tx_pipe_handle=0x%x",
+		    __func__, hdd_ipa->tx_pipe_handle);
+	ipa_disconnect_wdi_pipe(hdd_ipa->tx_pipe_handle);
+
+	HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
+		    "%s: Disconnect RX PIPE rx_pipe_handle=0x%x",
+		    __func__, hdd_ipa->rx_pipe_handle);
+	ipa_disconnect_wdi_pipe(hdd_ipa->rx_pipe_handle);
+
 	if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx))
 		hdd_ipa_uc_sta_reset_sta_connected(hdd_ipa);
 
@@ -2759,14 +2777,66 @@
  *
  * Return: 0 - Success
  */
-static int __hdd_ipa_uc_ssr_reinit(void)
+static int __hdd_ipa_uc_ssr_reinit(hdd_context_t *hdd_ctx)
 {
 
-	/* After SSR is complete, IPA UC can resume operation. But now wlan
-	 * driver will be unloaded and reloaded, which takes care of IPA cleanup
-	 * and initialization. This is a placeholder func if IPA has to resume
-	 * operations without driver reload.
-	 */
+	struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
+	int i;
+	struct hdd_ipa_iface_context *iface_context = NULL;
+	struct ol_txrx_pdev_t *pdev = NULL;
+
+	if (!hdd_ipa || !hdd_ipa_uc_is_enabled(hdd_ctx))
+		return 0;
+
+	pdev = cds_get_context(QDF_MODULE_ID_TXRX);
+	if (!pdev) {
+		HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "pdev is NULL");
+		return -EINVAL;
+	}
+
+	cdp_ipa_get_resource(cds_get_context(QDF_MODULE_ID_SOC),
+			cds_get_context(QDF_MODULE_ID_TXRX),
+			&hdd_ipa->ipa_resource);
+	if ((hdd_ipa->ipa_resource.ce_sr_base_paddr == 0) ||
+	    (hdd_ipa->ipa_resource.tx_comp_ring_base_paddr == 0) ||
+	    (hdd_ipa->ipa_resource.rx_rdy_ring_base_paddr == 0) ||
+	    (hdd_ipa->ipa_resource.rx2_rdy_ring_base_paddr == 0)) {
+		HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL,
+			"IPA UC resource alloc fail");
+		return -EINVAL;
+	}
+
+	/* Create the interface context */
+	for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
+		iface_context = &hdd_ipa->iface_context[i];
+		iface_context->hdd_ipa = hdd_ipa;
+		iface_context->cons_client =
+			hdd_ipa_adapter_2_client[i].cons_client;
+		iface_context->prod_client =
+			hdd_ipa_adapter_2_client[i].prod_client;
+		iface_context->iface_id = i;
+		iface_context->adapter = NULL;
+	}
+	for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) {
+		hdd_ipa->vdev_to_iface[i] = CSR_ROAM_SESSION_MAX;
+		hdd_ipa->vdev_offload_enabled[i] = false;
+	}
+
+	if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
+		hdd_ipa->resource_loading = false;
+		hdd_ipa->resource_unloading = false;
+		hdd_ipa->sta_connected = 0;
+		hdd_ipa->ipa_pipes_down = true;
+		hdd_ipa->uc_loaded = true;
+
+		if (hdd_ipa_uc_ol_init(hdd_ctx)) {
+			HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL,
+				    "Failed to setup pipes");
+			return -EINVAL;
+		}
+
+	}
+
 	return 0;
 }
 
@@ -2778,12 +2848,12 @@
  *
  * Return: 0 - Success
  */
-int hdd_ipa_uc_ssr_reinit(void)
+int hdd_ipa_uc_ssr_reinit(hdd_context_t *hdd_ctx)
 {
 	int ret;
 
 	cds_ssr_protect(__func__);
-	ret = __hdd_ipa_uc_ssr_reinit();
+	ret = __hdd_ipa_uc_ssr_reinit(hdd_ctx);
 	cds_ssr_unprotect(__func__);
 
 	return ret;
@@ -5373,6 +5443,7 @@
 	return ret;
 }
 
+
 /**
  * hdd_ipa_cleanup_pending_event() - Cleanup IPA pending event list
  * @hdd_ipa: pointer to HDD IPA struct